Running multiple SET statements in CTE? - sql

using SQL 2012
I have a CTE statement that give me incorrect results. Multiple records for each record_id may exist with different types. This seems to be skipping records and not updating all of them correctly:
WITH cte as (
SELECT
o.sname, o.type, o.record_id,
p.data1, p.data2, p.data3
FROM
table1 p
JOIN table2 o ON o.record_id = p.record_id
WHERE
o.record_id IN(1,2,3)
--AND (o.type = 123 or o.type = 456 or o.type = 789)
UPDATE cte
set data1 = (case when type = 123 then 1 else data1 end),
data2 = (case when type = 456 then 1 else data2 end),
data3 = (case when type = 378 then 1 else data3 end)
where type in (123,456,789)
Not sure why this happens.
What I am after is to look at only certain records and if a specific TYPE value exists, change the DATA value to 1 every time it is encountered for specific TYPES.
If I run the UPDATE part of the CTE this way, it works correctly, just not when together:
UPDATE cte
set data1 = (case when type = 123 then 1 else data1 end),
where type in (123)
UPDATE cte
set data2 = (case when type = 456 then 1 else data2 end)
where type in (456)
UPDATE cte
set data3 = (case when type = 789 then 1 else data3 end)
where type in (789)
Whats wrong?
Here are Tables and desired outputs:
TABLE1
record_id |type |sname
------------|-------|-----|
1 |123 |alpha
2 |123 |alpha
2 |456 |beta
3 |456 |beta
3 |789 |gamma
Table 2 is originally all zeros
Desired Output:
TABLE2
record_id| data1| data2| data3|
---------|-------|-------|-------|
1 |1 | 0 | 0
2 |1 | 1 | 0
3 |0 | 1 | 1
Actual Output:
TABLE2
record_id| data1| data2| data3|
---------|-------|-------|-------|
1 |1 | 0 | 0
2 |1 | 0 | 0
3 |0 | 1 | 0
Thanks,
MP

You can simply use aggregation in a subquery to check which type exists for a given record_id and then multitable update like this:
update t2
set t2.data1 = t1.data1,
t2.data2 = t1.data2,
t2.data3 = t1.data3
from table2 t2
join (
select record_id,
max(case when type = 123 then 1 else 0 end) as data1,
max(case when type = 456 then 1 else 0 end) as data2,
max(case when type = 789 then 1 else 0 end) as data3
from table1
group by record_id
) t1
on t1.record_id = t2.record_id;
Demo
Another way is using correlation with EXISTS:
update t2
set data1 = case when exists (select 1 from table1 t1 where t1.record_id = t2.record_id and t1.type = 123) then 1 else 0 end,
data2 = case when exists (select 1 from table1 t1 where t1.record_id = t2.record_id and t1.type = 456) then 1 else 0 end,
data3 = case when exists (select 1 from table1 t1 where t1.record_id = t2.record_id and t1.type = 789) then 1 else 0 end
from table2 t2;
Demo 2

Related

How to get 2 values of same num to 2 separate columns

I got table like this:
num |type|value
--------------
1 | a | 5
1 | b | 7
3 | c | 9
2 | a | 6
2 | b | 9
and want this kind of result:
num| value (a) | value (b)
-------------------------
1 | 5 | 7
2 | 6 | 9
You can use a self-join which will also remove the rows with just one value (num = 3 in your sample data)
select t1.num, t1.value as value_a, t2.value as value_b
from the_table t1
join the_table t2 on t1.num = t2.num and t2.type = 'b'
where t1.type = 'a'
You can use GROUP BY and CASE, as in:
select
num,
max(case when type = 'a' then value end) as value_a,
max(case when type = 'b' then value end) as value_b
from t
group by num
I'd join the table on itself, once for a and once for b
SELECT a.num, a.value, b.value
FROM mytable a
JOIN mytable b ON a.num = b.num AND a.type = 'a' AND b.type = 'b'

SQL Assign Custom values to those rows with similar IDs

|id|last|
|2 |NULL|
|2 |2018|
|3 |NULL|
|3 |NULL|
|4 |2011|
|4 |2013|
This is what my current table looks like. A new 'status' column is to be created for each 'id' that must have the below 3 values.
1 - If Similar id and only one NULL value
2 - If Similar id and no NULL value
0 - If Similar id and both NULL value
EXAMPLE: Id 2 will get 1, id 3 will be assigned 0 and id 4 will get 2. There can be only 2 similar ids in the id table (there are no 3 values of 2 or 4)
I could find the similar id, but having difficulties writing the cases
select id
from table
group by id
having count(id) = 2
We can determine the status values by using aggregation:
WITH cte AS (
SELECT id,
CASE WHEN COUNT(*) > 1 AND COUNT(CASE WHEN last IS NULL THEN 1 END) = 1
THEN 1
WHEN COUNT(*) > 1 AND COUNT(CASE WHEN last IS NULL THEN 1 END) = 0
THEN 2
WHEN COUNT(*) > 1 AND COUNT(CASE WHEN last IS NULL THEN 1 END) = COUNT(*)
THEN 0 ELSE -1 END AS status
FROM yourTable
GROUP BY id
)
SELECT t1.*, t2.status
FROM yourTable t1
INNER JOIN cte t2
ON t1.id = t2.id;
Note that I assign a status value of -1 to any id which does not meet one of the three criteria. This would include any id which only appears once, among other edge cases.
You can do it this way
select a.id, last,
case
when exists(select 1 from _table b where a.id = b.id and coalesce(b.last,0) <> coalesce(a.last,0) and (a.last is null or b.last is null))
then 1
when exists(select 1 from _table b where a.id = b.id
and coalesce(b.last,0) <> coalesce(a.last,0))
and not exists(select 1 from _table b where a.id = b.id
and b.last is null)
then 2
when exists(select 1 from _table b where a.id = b.id )
and exists(select 1 from _table b where a.id = b.id and b.last is null and a.last is null having count(*) =
(select count(*) from _table b where a.id = b.id))
then 0
end as status
from _table a
Output:
id last status
2 NULL 1
2 2018 1
3 NULL 0
3 NULL 0
4 2011 2
4 2013 2
If you want one row per id:
select id,
(case count(*) filter (value is null)
when 1 then 1
when 0 then 2
when 2 then 3
end) as status
from t
group by id;
If you want this as a column on the original data, use window functions:
select t.*,
(case count(*) filter (value is null) over (partition by id)
when 1 then 1
when 0 then 2
when 2 then 3
end) as status
from t;

SQL query to get data with condition

I am using a SQL Server database.
A | B | C
--+---+---
1 |11 | 0
1 |12 | 0
1 |13 | 0
2 |33 | 5
2 |34 | 10
2 |35 | 78
5 |45 | 0
5 |49 | 0
5 |51 | 1
8 |10 | 0
8 |14 | 2
8 |34 | 3
I am looking for sql query to fetch distinct A value which is having at least one value of C is zero but should not all the values would be zero.
In the above table I should get 5 & 8
At the moment for A value which is having all values are zero , I am doing like as below so something similar would be helpful
SUM(ABS(table.C)) = 0
If C is never negative:
select A
from mytable
group by A
having min(C) = 0
and max(C) > 0
db<>fiddle
If C can be negative:
select A
from mytable
group by A
having min(abs(C)) = 0
and max(abs(C)) > 0
db<>fiddle
And there are many other ways:
select distinct t0.A
from mytable t0
join mytable t1 on t1.A = t0.A
where t0.C = 0
and t1.C <> 0;
select distinct t0.A
from mytable t0
where t0.C = 0
and exists (
select *
from mytable t1
where t1.A = t0.A
and t1.C <> 0
);
try like below by using exists
select A from table
where exists (select 1 from table t2 where t1.A=t2.A
and t2.c=0)
group by A
having sum(c)<>0
I think this will work:
;with zeros as
(
select distinct colA
from table
where ColC=0
)
select distinct colA
from table
join zeros on table.ColA=zeros.ColA
where table.ColC <> 0
You can try:
select distinct a
from my_table t
where t.a in (select x.a from my_table x where x.c = 0)
and t.a in (select x.a from my_table x where x.c <> 0)

Remove and Identify Duplicate Records in SQL

I have some sample records below that I need to use the CASE WHEN statement to remove and identify the duplicate records in SQL.
Quantity Values Desc event ID
1 5 Blue 12550 577
1 5 bluee 12550 525
2 10 blu 12550 535
i would like to use a case statement to show the duplicate indicators such as:
Dup_Quantity Dup_Value Dup_Desc Quantity Values Desc event ID
Y Y N 1 5 Blue 12550 577
Y Y N 1 5 Bluee 12550 525
however, after using this script, the result still shows as:
Dup_Quantity Dup_Value Dup_Desc Quantity Values Desc event ID
Y Y N 1 5 Blue 12550 577
Y Y N 1 5 Bluee 12550 525
Y N N 2 10 Blu 12550 535
SELECT DISTINCT
CASE WHEN a.Quantity = b.Quantity THEN 'Y' ELSE 'N' END AS "Dup_Quantity",
CASE WHEN a.Values = b.Values THEN 'Y' ELSE 'N' END AS "Dup_Value",
CASE WHEN a.Desc = b.Desc THEN 'Y' ELSE 'N' END AS "Dup_Desc"
FROM Table1 a
INNER JOIN Table1 b ON a.event = b.event
WHERE (a.Quantity = b.Quantity OR a.Values = b.Values OR a.Desc = b.Desc)
AND a.ID <> b.ID
Basically, record with ID 535 stills shows up in the result. Would someone Please give me some pointers?
SQL Fiddle
MS SQL Server 2012 Schema Setup:
CREATE TABLE Table1
([Quantity] int, [Values] int, [Desc] varchar(5), [event] int, [ID] int)
;
INSERT INTO Table1
([Quantity], [Values], [Desc], [event], [ID])
VALUES
(1, 5, 'Blue', 12550, 577),
(1, 5, 'bluee', 12550, 525),
(2, 10, 'blu', 12550, 535)
;
Query 1:
SELECT
CASE WHEN (SELECT COUNT(*)
FROM Table1 t2
WHERE t1.Quantity = t2.Quantity AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
THEN 'Y' ELSE 'N' END AS Dup_Quantity,
CASE WHEN (SELECT COUNT(*)
FROM Table1 t2
WHERE t1."Values" = t2."Values" AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
THEN 'Y' ELSE 'N' END AS Dup_Value,
CASE WHEN (SELECT COUNT(*)
FROM Table1 t2
WHERE t1."Desc" = t2."Desc" AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
THEN 'Y' ELSE 'N' END AS Dup_Desc,
*
FROM Table1 t1
WHERE
(SELECT COUNT(*)
FROM Table1 t2
WHERE t1.Quantity = t2.Quantity AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
OR
(SELECT COUNT(*)
FROM Table1 t2
WHERE t1."Values" = t2."Values" AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
OR
(SELECT COUNT(*)
FROM Table1 t2
WHERE t1."Desc" = t2."Desc" AND
t1.ID <> t2.ID AND t1.event = t2.event) > 0
Results:
| DUP_QUANTITY | DUP_VALUE | DUP_DESC | QUANTITY | VALUES | DESC | EVENT | ID |
|--------------|-----------|----------|----------|--------|-------|-------|-----|
| Y | Y | N | 1 | 5 | Blue | 12550 | 577 |
| Y | Y | N | 1 | 5 | bluee | 12550 | 525 |
Your query returns:
Dup_Quantity Dup_Value Dup_Desc
Y Y N
However I don't get what you want to do here, the correct version of it is:
SELECT
CASE WHEN a."Quantity" = b."Quantity" THEN 'Y' ELSE 'N' END AS "Dup_Quantity",
CASE WHEN a."Values" = b."Values" THEN 'Y' ELSE 'N' END AS "Dup_Value",
CASE WHEN a."Desc" = b."Desc" THEN 'Y' ELSE 'N' END AS "Dup_Desc",
a.*
FROM Table1 a
INNER JOIN Table1 b ON b.event = a.event
WHERE (a."Quantity" = b."Quantity" OR a."Values" = b."Values" OR a."Desc" = b."Desc")
AND a.ID <> b.ID
If you want to get duplicated rows in terms of Quantity, Values and Desc:
SELECT
a.*
FROM Table1 a
INNER JOIN Table1 b ON b.event = a.event
WHERE (a."Quantity" = b."Quantity" AND a."Values" = b."Values" AND a."Desc" = b."Desc")
AND a.ID <> b.ID

Sql Count by multiple Where condition

i've really bad problem with this sql query.
base on my tables i need some thing like this result:
table1
Id | Type | Size |Count | OwnerId
___________________________________
1 A 1 12 1
2 A 2 12 1
3 B 1 14 1
4 B 1 20 1
5 A 1 12 2
6 A 1 17 2
table2
Id | name
_________
1 A
2 B
The Result
______________________
Name | Size1Type1 Count | Size2Type1 Count | Size1Type2 Count
thanks indeeeeed .
You did not specify what RDBMS you are using but you should be able to get the result by implementing an aggregate function with a CASE statement. This process is similar to a PIVOT:
select t2.name,
sum(case when t1.size = 1 and t1.type = 'a' then 1 else 0 end) Size1Type1Count,
sum(case when t1.size = 2 and t1.type = 'a' then 1 else 0 end) Size2Type1Count,
sum(case when t1.size = 1 and t1.type = 'b' then 1 else 0 end) Size1Type2Count,
sum(case when t1.size = 2 and t1.type = 'b' then 1 else 0 end) Size2Type2Count
from table1 t1
inner join table2 t2
on t1.ownerid = t2.id
group by t2.name
See SQL Fiddle with Demo
Result:
| NAME | SIZE1TYPE1COUNT | SIZE2TYPE1COUNT | SIZE1TYPE2COUNT | SIZE2TYPE2COUNT |
--------------------------------------------------------------------------------
| A | 1 | 1 | 2 | 0 |
| B | 2 | 0 | 0 | 0 |
If you want to include your count field, then you would use something like this:
select t2.name,
sum(case when t1.size = 1 and t1.type = 'a' then "Count" end) Size1Type1Count,
sum(case when t1.size = 2 and t1.type = 'a' then "Count" end) Size2Type1Count,
sum(case when t1.size = 1 and t1.type = 'b' then "Count" end) Size1Type2Count,
sum(case when t1.size = 2 and t1.type = 'b' then "Count" end) Size2Type2Count
from table1 t1
inner join table2 t2
on t1.ownerid = t2.id
group by t2.name;
See SQL Fiddle with Demo
Result:
| NAME | SIZE1TYPE1COUNT | SIZE2TYPE1COUNT | SIZE1TYPE2COUNT | SIZE2TYPE2COUNT |
--------------------------------------------------------------------------------
| A | 12 | 12 | 34 | (null) |
| B | 29 | (null) | (null) | (null) |
Or you could even perform multiple joins on the tables to get the result that you want:
select t2.name,
sum(t1_a1."count") Size1Type1Count,
sum(t1_a2."count") Size2Type1Count,
sum(t1_b1."count") Size1Type2Count,
sum(t1_b2."count") Size2Type2Count
from table2 t2
left join table1 t1_a1
on t1_a1.ownerid = t2.id
and t1_a1.size = 1
and t1_a1.type = 'a'
left join table1 t1_a2
on t1_a2.ownerid = t2.id
and t1_a2.size = 2
and t1_a2.type = 'a'
left join table1 t1_b1
on t1_b1.ownerid = t2.id
and t1_b1.size = 1
and t1_b1.type = 'b'
left join table1 t1_b2
on t1_b2.ownerid = t2.id
and t1_b2.size = 2
and t1_b2.type = 'b'
group by t2.name
See SQL Fiddle with Demo
SELECT Name, Type, Size, SUM(Count) AS 'Count' FROM Table1, Table2
WHERE Table1.OwnerID = Tabel2.Id
GROUP BY Name, Type, Size