SQL - Multi Where clauses [duplicate] - sql-server

Are the two statements below equivalent?
SELECT [...]
FROM [...]
WHERE some_col in (1,2,3,4,5) AND some_other_expr
and
SELECT [...]
FROM [...]
WHERE some_col in (1,2,3) or some_col in (4,5) AND some_other_expr
Is there some sort of truth table I could use to verify this?

And has precedence over Or, so, even if a <=> a1 Or a2
Where a And b
is not the same as
Where a1 Or a2 And b,
because that would be Executed as
Where a1 Or (a2 And b)
and what you want, to make them the same, is the following (using parentheses to override rules of precedence):
Where (a1 Or a2) And b
Here's an example to illustrate:
Declare #x tinyInt = 1
Declare #y tinyInt = 0
Declare #z tinyInt = 0
Select Case When #x=1 OR #y=1 And #z=1 Then 'T' Else 'F' End -- outputs T
Select Case When (#x=1 OR #y=1) And #z=1 Then 'T' Else 'F' End -- outputs F
For those who like to consult references (in alphabetic order):
Microsoft Transact-SQL operator precedence
Oracle MySQL 9 operator precedence
Oracle 10g condition precedence
PostgreSQL operator Precedence
SQL as understood by SQLite

I'll add 2 points:
"IN" is effectively serial ORs with parentheses around them
AND has precedence over OR in every language I know
So, the 2 expressions are simply not equal.
WHERE some_col in (1,2,3,4,5) AND some_other_expr
--to the optimiser is this
WHERE
(
some_col = 1 OR
some_col = 2 OR
some_col = 3 OR
some_col = 4 OR
some_col = 5
)
AND
some_other_expr
So, when you break the IN clause up, you split the serial ORs up, and changed precedence.

Arithmetic operators
Concatenation operator
Comparison conditions
IS [NOT] NULL, LIKE, [NOT] IN
[NOT] BETWEEN
Not equal to
NOT logical condition
AND logical condition
OR logical condition
You can use parentheses to override rules of precedence.

Query to show a 3-variable boolean expression truth table :
;WITH cteData AS
(SELECT 0 AS A, 0 AS B, 0 AS C
UNION ALL SELECT 0,0,1
UNION ALL SELECT 0,1,0
UNION ALL SELECT 0,1,1
UNION ALL SELECT 1,0,0
UNION ALL SELECT 1,0,1
UNION ALL SELECT 1,1,0
UNION ALL SELECT 1,1,1
)
SELECT cteData.*,
CASE WHEN
(A=1) OR (B=1) AND (C=1)
THEN 'True' ELSE 'False' END AS Result
FROM cteData
Results for (A=1) OR (B=1) AND (C=1) :
A B C Result
0 0 0 False
0 0 1 False
0 1 0 False
0 1 1 True
1 0 0 True
1 0 1 True
1 1 0 True
1 1 1 True
Results for (A=1) OR ( (B=1) AND (C=1) ) are the same.
Results for ( (A=1) OR (B=1) ) AND (C=1) :
A B C Result
0 0 0 False
0 0 1 False
0 1 0 False
0 1 1 True
1 0 0 False
1 0 1 True
1 1 0 False
1 1 1 True

Here's a variant of the '3-variable truth table' using booleans
WITH truth_values AS
(SELECT FALSE AS A,
FALSE AS B,
FALSE AS C
UNION ALL SELECT FALSE,
FALSE,
TRUE
UNION ALL SELECT FALSE,
TRUE,
FALSE
UNION ALL SELECT FALSE,
TRUE,
TRUE
UNION ALL SELECT TRUE,
FALSE,
FALSE
UNION ALL SELECT TRUE,
FALSE,
TRUE
UNION ALL SELECT TRUE,
TRUE,
FALSE
UNION ALL SELECT TRUE,
TRUE,
TRUE),
logics AS
(SELECT truth_values.*,
a
OR b
AND c AS no_parens, (a
OR b)
AND c AS or_parens
FROM truth_values)
SELECT *,
no_parens != or_parens AS parens_made_a_difference
FROM logics
ORDER BY a,
b,
c
With these results:
#
A
B
C
no_parens
or_parens
parens_made_a_difference
1
false
false
false
false
false
false
2
false
false
true
false
false
false
3
false
true
false
false
false
false
4
false
true
true
true
true
false
5
true
false
false
true
false
true
6
true
false
true
true
true
false
7
true
true
false
true
false
true
8
true
true
true
true
true
false
If 'parens_made_a_difference' is true, then the parentheses made a difference.

Related

SQLite SELECT statement ignores WHERE clause [duplicate]

Are the two statements below equivalent?
SELECT [...]
FROM [...]
WHERE some_col in (1,2,3,4,5) AND some_other_expr
and
SELECT [...]
FROM [...]
WHERE some_col in (1,2,3) or some_col in (4,5) AND some_other_expr
Is there some sort of truth table I could use to verify this?
And has precedence over Or, so, even if a <=> a1 Or a2
Where a And b
is not the same as
Where a1 Or a2 And b,
because that would be Executed as
Where a1 Or (a2 And b)
and what you want, to make them the same, is the following (using parentheses to override rules of precedence):
Where (a1 Or a2) And b
Here's an example to illustrate:
Declare #x tinyInt = 1
Declare #y tinyInt = 0
Declare #z tinyInt = 0
Select Case When #x=1 OR #y=1 And #z=1 Then 'T' Else 'F' End -- outputs T
Select Case When (#x=1 OR #y=1) And #z=1 Then 'T' Else 'F' End -- outputs F
For those who like to consult references (in alphabetic order):
Microsoft Transact-SQL operator precedence
Oracle MySQL 9 operator precedence
Oracle 10g condition precedence
PostgreSQL operator Precedence
SQL as understood by SQLite
I'll add 2 points:
"IN" is effectively serial ORs with parentheses around them
AND has precedence over OR in every language I know
So, the 2 expressions are simply not equal.
WHERE some_col in (1,2,3,4,5) AND some_other_expr
--to the optimiser is this
WHERE
(
some_col = 1 OR
some_col = 2 OR
some_col = 3 OR
some_col = 4 OR
some_col = 5
)
AND
some_other_expr
So, when you break the IN clause up, you split the serial ORs up, and changed precedence.
Arithmetic operators
Concatenation operator
Comparison conditions
IS [NOT] NULL, LIKE, [NOT] IN
[NOT] BETWEEN
Not equal to
NOT logical condition
AND logical condition
OR logical condition
You can use parentheses to override rules of precedence.
Query to show a 3-variable boolean expression truth table :
;WITH cteData AS
(SELECT 0 AS A, 0 AS B, 0 AS C
UNION ALL SELECT 0,0,1
UNION ALL SELECT 0,1,0
UNION ALL SELECT 0,1,1
UNION ALL SELECT 1,0,0
UNION ALL SELECT 1,0,1
UNION ALL SELECT 1,1,0
UNION ALL SELECT 1,1,1
)
SELECT cteData.*,
CASE WHEN
(A=1) OR (B=1) AND (C=1)
THEN 'True' ELSE 'False' END AS Result
FROM cteData
Results for (A=1) OR (B=1) AND (C=1) :
A B C Result
0 0 0 False
0 0 1 False
0 1 0 False
0 1 1 True
1 0 0 True
1 0 1 True
1 1 0 True
1 1 1 True
Results for (A=1) OR ( (B=1) AND (C=1) ) are the same.
Results for ( (A=1) OR (B=1) ) AND (C=1) :
A B C Result
0 0 0 False
0 0 1 False
0 1 0 False
0 1 1 True
1 0 0 False
1 0 1 True
1 1 0 False
1 1 1 True
Here's a variant of the '3-variable truth table' using booleans
WITH truth_values AS
(SELECT FALSE AS A,
FALSE AS B,
FALSE AS C
UNION ALL SELECT FALSE,
FALSE,
TRUE
UNION ALL SELECT FALSE,
TRUE,
FALSE
UNION ALL SELECT FALSE,
TRUE,
TRUE
UNION ALL SELECT TRUE,
FALSE,
FALSE
UNION ALL SELECT TRUE,
FALSE,
TRUE
UNION ALL SELECT TRUE,
TRUE,
FALSE
UNION ALL SELECT TRUE,
TRUE,
TRUE),
logics AS
(SELECT truth_values.*,
a
OR b
AND c AS no_parens, (a
OR b)
AND c AS or_parens
FROM truth_values)
SELECT *,
no_parens != or_parens AS parens_made_a_difference
FROM logics
ORDER BY a,
b,
c
With these results:
#
A
B
C
no_parens
or_parens
parens_made_a_difference
1
false
false
false
false
false
false
2
false
false
true
false
false
false
3
false
true
false
false
false
false
4
false
true
true
true
true
false
5
true
false
false
true
false
true
6
true
false
true
true
true
false
7
true
true
false
true
false
true
8
true
true
true
true
true
false
If 'parens_made_a_difference' is true, then the parentheses made a difference.

SQL Server: increment row number only one value

I have this table:
Id status
-----------
1 true
2 false
3 true
4 true
5 false
I need output like this:
Id status count
-----------------
1 true 1
2 false 1
3 true 2
4 true 3
5 false 3
So I need to increment only true and but not false
You can use the window functions ( well worth your time to get familiar with)
Example
Declare #YourTable Table ([Id] int,[status] varchar(50)) Insert Into #YourTable Values
(1,'true')
,(2,'false')
,(3,'true')
,(4,'true')
,(5,'false')
Select *
,count = sum(case when status='true' then 1 else 0 end) over (order by id)
From #YourTable
Returns
Id status count
1 true 1
2 false 1
3 true 2
4 true 3
5 false 3
Edit... If [status] is a bit
...
,count = sum(convert(int,status)) over (order by id)
...

I want o get one case per account

I have that query:
SELECT Id,AccountId,IsEscalated FROM Case WHERE AccountId != null AND IsClosed = FALSE ORDER BY AccountId,IsEscalated DESC
That return this data
Id AccountId IsEscalated
1 1 true
2 1 false
3 1 false
4 2 false
5 2 false
6 3 true
But I want recive this
Id AccountId IsEscalated
1 1 true
4 2 false
6 3 true

Calculate Type of the member in a table (Self Join/Case When or any other possible way)

Here is the Table :
If OBJECT_ID ('tempdb..##SelfCount') Is not null
drop table #SelfCount
create table #SelfCount (CanID int , CanType int)
insert into #SelfCount (CanID, CanType)
values
(1,0),
(2,0),
(1,1),
(2,1),
(1,2),
(1,2),
(1,0)
CanID CanType
1 0
2 0
1 1
2 1
1 2
1 2
1 0
I'm Expecting the result to be like this
CanID Self Spouse Dependent
1 2 1 2
2 1 1 0/NULL --It doesn't matter if it's nUll or 0
I wrote this query
select CanID,
case
When CanType = 0 then count(CanType)
end as [self],
case
when CanType = 1 then count(CanType)
end as [Spouse],
Case
When CanType = 2 then count(CanType)
end as [Dependent]
from #SelfCount
Group by CanID, CanType
But the Result Set is like this :
CanID Self Spouse Dependent
1 2 NULL NULL
2 1 NULL NULL
1 NULL 1 NULL
2 NULL 1 NULL
1 NULL NULL 2
I've tried the Recursive method, If anyone could provide both Recursive as well as Set processing method, it'll be greatly appreciated.
By including the CanType in the group by clause, you're getting a separate result row per distinct value of CanType (and CanId, since it's also contained in the group by clause).
Instead, you should only have CanId in the group by clause, and apply different counts on case expressions:
SELECT CanID,
COUNT (CASE CanType WHEN 0 THEN 1 END) AS [Self],
COUNT (CASE CanType WHEN 1 THEN 1 END) AS [Spouse],
COUNT (CASE CanType WHEN 2 THEN 1 END) AS [Dependent],
FROM #SelfCount
GROUP BY CanID
May be this is what you need:
select CanID,
sum(case when CanType = 0 then 1 else 0 end) as [Self],
sum(case when CanType = 1 then 1 else 0 end) as [Spouse],
sum(case when CanType = 2 then 1 else 0 end) as [Dependent]
from #SelfCount
group by CanID
You can try with PIVOT:
select
CanID,
[0] as Self,
[1] as Spouse,
[2] as Dependent
from tab
pivot
(
count (CanType)
for CanType IN ([0], [1], [2])
) as pvt
Basically, it will group by all columns not declared inside the PIVOT clause (actually, just the CanID) and then create three aggregation COUNT columns, one FOR each CanType IN the list of values. If you need to count more values, just define them in the IN clause and in the SELECT clause.

mssql query for checking whether the sum is even, odd or zero?

I need to get:
0 if sum(apples) is 0
1 if sum(apples) is odd
2 if sum(apples) is
even
how do i write such a query ?
select answer =
case sum(apples)%2
when 1 then 1
else 2
end
from fruits
I need a third option 0 if the sum is zero ...
My problem is that sum(apples)%2 returns 0 both in even and zero cases.
Thanks
You need to change your query to the following way.
select answer =
case
WHEN sum(apples)=0 then 0
WHEN sum(apples)%2 = 1 then 1
else 2
end
from fruits
as per MySQL Documentation you have two option for syntax, you just needed to change to second option
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
or
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list
END CASE
You may be able to use this little snippet of code in the way that you want...
declare #n int = 0
select case #n when 0 then 'zero' else (case (#n%2) when 1 then 'odd' else 'even' end) end
try it with other values for #n.
Depending on how apples column is defined (it's mandatory or it allows NULLs) SUM could return a non-NULL value or it could return NULL:
SELECT x.OrderID,
SUM(x.Qty) AS SumOfQty,
CASE
WHEN SUM(x.Qty) = 0 THEN 0
WHEN SUM(x.Qty) % 2 = 1 THEN 1
WHEN SUM(x.Qty) % 2 = 0 THEN 2
ELSE -1 -- SUM(x.Qty) IS NULL
END AS CaseSumOfQty
FROM (
SELECT 1, 100 UNION ALL
SELECT 2, 200 UNION ALL
SELECT 2, 301 UNION ALL
SELECT 3, 0 UNION ALL
SELECT 4, NULL
) x(OrderID, Qty)
GROUP BY x.OrderID;
Output:
OrderID SumOfQty CaseSumOfQty
------- ----------- ------------
1 100 2
2 501 1
3 0 0
4 NULL -1 -- SUM(x.Qty) IS NULL

Resources