SQL query to get data with condition - sql

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)

Related

Get only rows where data is the max value

I have a table like this:
treatment | patient_id
3 | 1
3 | 1
3 | 1
2 | 1
2 | 1
1 | 1
2 | 2
2 | 2
1 | 2
I need to get only rows on max(treatment) like this:
treatment | patient_id
3 | 1
3 | 1
3 | 1
2 | 2
2 | 2
The patient_id 1 the max(treatment) is 3
The patient_id 2 the max(treatment) is 2
You can for example join on the aggregated table using the maximal value:
select t.*
from tmp t
inner join (
select max(a) max_a, b
from tmp
group by b
) it on t.a = it.max_a and t.b = it.b;
Here's the db fiddle.
Try this :
WITH list AS
( SELECT patient_id, max(treatment) AS treatment_max
FROM your_table
GROUP BY patient_id
)
SELECT *
FROM your_table AS t
INNER JOIN list AS l
ON t.patient_id = l.patient_id
AND t.treatment = l.treatment_max
You can use rank:
with u as
(select *, rank() over(partition by patient_id order by treatment desc) r
from table_name)
select treatment, patient_id
from u
where r = 1;
Fiddle
use corelated subquery
select t1.* from table_name t1
where t1.treatment=( select max(treatment) from table_name t2 where t1.patient_id=t2.patient_id
)

single column value in multiple columns

ID|Class | Number
--+------+---------
1 | 1 | 58.2
2 | 1 | 85.4
3 | 2 | 28.2
4 | 2 | 55.4
The desired result would be:
Column1 |Number | Column2 | Number
--------+-------+---------+---------
1 | 58.2 | 2 |28.2
1 | 85.4 | 2 |55.4
What would be the required SQL?
You can user row_number() and aggregate:
select 1, max(case when seqnum % 2 = 1 then number end),
2, max(case when seqnum % 2 = 0 then number end)
from (select t.*,
row_number() over (partition by class order by id) as seqnum
from t
) t
group by ceiling(seqnum / 2.0);
The aggregation uses arithmetic to put pairs of rows for each class into one row.
try this
SELECT 1 AS Column1,t2.Number,2 AS Column2,t1.Number
FROM
(
SELECT *
FROM test11
) t2
INNER JOIN
(
SELECT *
FROM test11
) t1
ON t1.Class = t2.Class
WHERE t1.ID < t2.ID
ORDER BY t1.ID DESC
Demo in db<>fiddle

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;

Running multiple SET statements in CTE?

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