SQL Server Select CASE WHEN inside where condition - sql-server-2012

My code is like this
SELECT A, B, C
FROM tb_1
WHERE C = (SELECT CASE WHEN (B > C) THEN C ELSE NULL END FROM tb_2)
I want to select row from tb_1 with specified condition. When result of subquery is value of column C, it works well. But when the result is NULL, it cannot select the data. Because SQL Server cannot execute something like this
SELECT A, B, C
FROM tb_1
WHERE C = NULL
but, it should be like this
SELECT A, B, C
FROM tb_1
WHERE C IS NULL
Can anybody help me? I still want to insert subquery (select case when) to that condition
Thanks

The table tb_2 design is not clear from your question. Assuming the tb_2 structure be same as tb_1, I think the following would work, but it all depends on your data (especially values in the column C). For example, if the values saved in C never be -9999, then you could use ISNULL in the WHERE clause as below. However, I would recommend to avoid subqueries where possible.
WHERE ISNULL(C, -9999) IN (SELECT CASE WHEN (B > C) THEN ISNULL(C, -9999) ELSE -9999 END FROM #t2)
Illustration:
GO
DECLARE #T1 TABLE (A INT, B INT, C INT)
INSERT INTO #T1 (A, B)VALUES (10, 20),(1, 2)
DECLARE #T2 TABLE (A INT, B INT, C INT)
INSERT INTO #T2 (A, B)VALUES (10, 20),(1, 2)
SELECT A, B, C
FROM #t1
WHERE ISNULL(C, -9999) IN (SELECT CASE WHEN (A > B) THEN ISNULL(C, -9999) ELSE -9999 END FROM #t2)

Related

Using multiple CTE with multiple temp tables

In Windows Server, I am trying to gather data using multiple CTEs insert them into a few temp tables to later on perform a join. Below is what I got. :
------TEMP TABLE SET UP------
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#LEFT')
)
BEGIN
DROP TABLE #LEFT
END
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#RIGHT')
)
BEGIN
DROP TABLE #RIGHT
END
------TEMP TABLE SET UP END------
------CTE SET UP------
; with
CTEfirst (1a, b, c, d) as
(select 1a, b, c, d from tableA)
, CTEone (a, b, c) as
(select a, b, c from table1)
),
CTEtwo (a, b, c) as (
(select a, b, c from table2)
),
CTEthree (a, b, c) as (
(select a, b, c from table3)
------CTE SET UP END------
select * into #LEFT from CTEone
union
select * from CTEtwo
union
select * from CTEthree
-----------------------------
/*At this point I am getting the issue to recognize CTEfirst when attempting to insert data into #RIGHT temp table unless I move the below portion below the previous section (prior to the unions) but then would encounter the issue of the overall query not recognizing the next CTE, CTEone.*/
select * into #RIGHT from CTEfirst
Thank you
you have declared cte but it is empty
; with
CTEfirst (a, b, c, d)
as ( select ...) --<-- missing cte definiation here
, CTEone (a, b, c) as
(select a, b, c from table1)
),
You cannot refer to the same CTE for more than one unattached select statement.
Your first query ends when you insert into #left.
After that you cannot run a new select statement referring to the same (unattached) CTEs.
Think of CTEs as reformatted sub-queries. If you want data loaded into multiple temp tables, I wouldn't use CTEs in the first place. Just insert into the temp tables directly.

max function does not when having case when clause

i have two tables.
one is as below
table a
ID, count
1, 123
2, 123
3, 123
table b
ID, count
table b is empty
when using
SELECT CASE
WHEN isnotnull(max(b.count)) THEN max(a.count) + max(b.count)
ELSE max(a.count)
FROM a, b
the only result is always NULL
i am very confused. why?
You don't need to use a JOIN, a simple SUM of two sub-queries will give you your desired result. Since you only add MAX(b.count) when it is non-NULL, we can just add it all the time but COALESCE it to 0 when it is NULL.
SELECT COALESCE((SELECT MAX(count) FROM b), 0) + (SELECT MAX(count) FROM a)
Another way to make this work is to UNION the count values from each table:
SELECT COALESCE(MAX(bcount), 0) + MAX(acount)
FROM (SELECT count AS acount, NULL AS bcount FROM a
UNION
SELECT NULL AS acount, count AS bcount FROM b) u
Note that if you use a JOIN it must be a FULL JOIN. If you use a LEFT JOIN you risk not seeing all the values from table b. For example, consider the case where table b has one entry: ID=4, count=456. A LEFT JOIN on ID will not include this value in the result table (since table a only has ID values of 1,2 and 3) so you will get the wrong result:
CREATE TABLE a (ID INT, count INT);
INSERT INTO a VALUES (1, 123), (2, 123), (3, 123);
CREATE TABLE b (ID INT, count INT);
INSERT INTO b VALUES (4, 456);
SELECT COALESCE(MAX(b.count), 0) + MAX(a.count)
FROM a
LEFT JOIN b ON a.ID = b.ID
Output
123 (should be 579)
To use a FULL JOIN you would write
SELECT COALESCE(MAX(b.count), 0) + MAX(a.count)
FROM a
FULL JOIN b ON a.ID = b.ID
Since, tableb is empty, max(b.count) will return NULL. And any operation done with NULL, results in NULL.
So, max(a.count) + max(b.count) is NULL.(this is 123 + NULL which will be NULL always). Hence, your query is returning NULL.
Just use a coalesce to assign a default value whenever NULL comes.
use coalesce() function and explicit join, avoid coma separated table name type old join method
select coalesce(max(a.count)+max(b.count),max(a.count))
from a left join b on a.id=b.id
Use left join
SELECT coalesce(max(a.count) + max(b.count),max(a.count))
FROM a left join b a.id=b.id

TSQL select max from 3 columns and then inner join a column

How do I do this:
in table A I have 3 columns with integer values: a,b,c
in table B I have 3 columns with integer values: x,y,z
I want to select max of (a,b,c) and inner join the corresponding value from x,y,z.
Example:
a = 1, b = 2, c = 3
x = 7, y = 8, z = 9
result:
table with two columns
firstColumn | secondColumn
c | 9
explanation: c is the max of a,b,c and we take the name, not the value
9 is the value from the second table what we need
thanks in advance
ps I am using sql server 2014
Edit: I tried to make an example with excel table
Unless both tables have only 1 row you'll propably don't want to do a CROSS JOIN that would join all records from table1 to all from table2.
So my guess is that you're looking for something like this:
select
case
when c > isnull(a,0) and c > isnull(b,0) then 'c'
when b > isnull(a,0) then 'b'
when a is not null then 'a'
end as firstColumn,
case
when c > isnull(a,0) and c > isnull(b,0) then z
when b > isnull(a,0) then y
when a is not null then x
end as secondColumn
from table1 t1
join table2 t2 on t1.table2_id = t2.id
Just a bit of test data:
declare #table1 table (id int identity(1,1), a int, b int, c int, table2_id int default 1);
declare #table2 table (id int, x int, y int, z int);
insert into #table1 (a, b, c) values
(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1),
(4,5,5),(5,4,5),(5,5,4),(4,5,4),(4,4,5),(4,4,4),
(6,7,null),(6,null,7),(null,6,7),
(8,null,null),(null,8,null),(null,null,8),(null,null,null);
insert into #table2 (id, x, y, z) values (1,100,200,300);
The table structure you have shown us does not support your requirement. You need something that joins the rows in one table to the other.
If this exists you can then use (demo)
SELECT t1label,
t2col
FROM TableA TA
JOIN TableB TB
ON TA.rownum = TB.rownum
CROSS APPLY (SELECT TOP 1 *
FROM (VALUES('A', TA.a, TB.x),
('B', TA.b, TB.y),
('C', TA.c, TB.z)) v(t1label, t1col, t2col)
ORDER BY t1col DESC) CA
In the event a TableA row has two or more columns with the same maximum value it is undeterministic which will be selected.

Sql update column from column update in single statement

I have a table with 50 columns, lets's say a,b,c,d etc.
I want to update b from a and c from the new value of b
,so
b=b+a,c=c+b ,d = c+ d,.. etc
I don't want to make an update like
Update [table] set b=b+a, c= c+b+a.. etc
because for each column update I must write a huge calculated formula, which will get bigger and more complex for each column.
The table I want to update has about 50 million rows so I think that creating multiple update statements will be a suicide performance wise.
How should I handle this?
Do you think using variables is a good idea?
Thank you and sorry for my English.
Note: Sorry for not being clear about my question.
There are 50 new columns in an existing table.
The first new column, a, is calculated using a join with other tables.
The second new column, b, is calculated by adding the result to the new value of a, to a calculation I want to make using a join with other tables (the same tables as the first update).
The sames logic applies for calculating the values for all 50 columns.
UPDATED:
Thanks for updating your question. Definitely, use SUBQUERIES in your UPDATE statement to do most of the work. You can utilize indexes in your queries through SARGs in your ON/WHERE predicates.
Since your logic is self-dependent on the other tables for columns, something like the following will help:
CREATE TABLE #TABLE1 (ColA INT, ID INT IDENTITY(1,1) )
INSERT INTO #TABLE1 (ColA ) VALUES (1)
CREATE TABLE #TABLE2 (ColB INT, ID INT IDENTITY(1,1) )
INSERT INTO #TABLE2 (ColB) VALUES (4)
CREATE TABLE #TABLE3 (ColC INT, ID INT IDENTITY(1,1) )
INSERT INTO #TABLE3 (ColC) VALUES (10)
SELECT ColC + B.ColB AS ColC, ColC, B.ColB, B.ColA, B.ORIGINAL, B.ID
FROM #TABLE3 A
RIGHT OUTER JOIN (SELECT ColB + B.ColA AS ColB, ColA, ORIGINAL, B.ID
FROM #TABLE2 A
RIGHT OUTER JOIN (SELECT ColA + ColB AS ColA, ColB AS ORIGINAL, A.ID
FROM #TABLE1 A
INNER JOIN #TABLE2 B ON A.ID = B.ID) B ON A.ID = B.ID ) B ON A.ID = B.ID
Note that for simplicity I just assumed the tables had the same ID columns, as I kept the inner subquery ID in the list. SQL goes from right to left (inner queries first), so keep that in mind.
It might be a long series of joins, but at least most of repetitive logic will be handles inside the subqueries themselves. OUTER JOINS make sense, since you want to keep the value of the inner query and compare that new computed value with the next outer subquery.
You can try using update from select like this.
UPDATE T
SET a = T.a
,b = T.b
,c = T.c
,d = T.d
...
...
SELECT a
,b = b + a
,c = c + b
,d = d + c
...
...
FROM yourtable T

Select distinct on multiple columns simultaneously, and keep one column in PostgreSQL

For a table such as this:
tblA
A,B,C
1,2,t3a
1,3,d4g
1,2,b5e
1,3,s6u
I want to produce a table that selects distinct on both A and B simultaneously, and still keep one value of C, like so:
tblB
A,B,C
1,2,t3a
1,3,d4g
Seems like this would be simple, but not finding it for the life of me.
DROP TABLE IF EXISTS tblA CASCADE;
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA;
When you use DISTINCT ON you should have ORDER BY:
SELECT DISTINCT ON (A,B), C
INTO tblB
FROM tblA
ORDER BY A, B;
This should do the trick
CREATE TABLE tblB AS (
SELECT A, B, max(C) AS max_of_C FROM tblA GROUP BY A, B
)
Use a view to do the distinct and then join it to the original table to pick one row of column C. Inserting into the target is left for you to figure out. Oh, and you could pick up multiple columns from t, not just c - the only thing is that your subquery needs to find a way to limit it to only one row.
create table t (a int, b int, c int);
create view tv as select distinct a, b from t;
insert into t (a, b, c) values(1, 2, 10);
insert into t (a, b, c) values(1, 2, 20);
insert into t (a, b, c) values(1, 3, 30);
insert into t (a, b, c) values(1, 3, 40);
CREATE TABLE tblB AS (
select tv.a, tv.b, t.c from tv, t
where tv.a = t.a and tv.b = t.b
/* pick smallest ctid which is a unique row id built into postgres */
and t.ctid = (select min(ctid) from t s where s.a = t.a and s.b = t.b);
)