I have a SQL dataset that looks like this:
SourceId SomeContent
-------------------
1 aaa
2 bbb
3 ccc
4 ddd
SourceId ConditionType CondidionValue
-------------------------------
1 1 2
1 2 200
2 1 3
2 2 201
3 1 4
I need to select the SourceId that have matching specific key,
e.g. (ConditionType=1 and ConditionValue=2) and (ConditionType=2 and ConditionValue=200 ) should return sourceId = 1). Query with specified key can match only one SourceId.
I'm trying to do it this way:
SELECT SourceId
FROM ConditionData
where ConditionType = 2 and ConditionValue = 200
and SourceId in(
SELECT SourceId
FROM ConditionData
where (ConditionType = 1 and ConditionValue = 2))
Is there more elegant query to get it?
You could use aggregation:
SELECT SourceId
FROM ConditionData
WHERE (ConditionType = 2 and ConditionValue = 200)
OR (ConditionType = 1 and ConditionValue = 2)
GROUP BY SourceId
HAVING COUNT(1) = 2 -- Alternatively: COUNT(1) > 1
I think you can use INNER JOIN for each condition
SELECT DISTINCT t1.SourceId
FROM table1 AS t1
INNER JOIN table2 AS condition1 ON t1.SourceId = condition1.SourceId AND condition1.ConditionType = 1 AND condition1.CondidionValue = 2
INNER JOIN table2 AS condition2 ON t1.SourceId = condition2.SourceId AND condition2.ConditionType = 2 AND condition2.CondidionValue = 200
Related
I'm using Microsoft SQL Server and I have a table shown below in my database:
Id groupName flag type
--------------------------------
1 aaa 0 0
2 aaa 1 0
3 aaa 0 0
4 bbb 0 0
5 bbb 0 0
6 bbb 0 0
I'd like to update the type column values based on the count of specific records in the same table.
Assuming that the records are grouped by their groupName, if a group has at least 1 record whose flag = 1, the typevalues of all the records in the same group should be 1, else 0.
In my case, I'd like to get the following output.
Id groupName flag type
--------------------------------
1 aaa 0 1
2 aaa 1 1
3 aaa 0 1
4 bbb 0 0
5 bbb 0 0
6 bbb 0 0
How can I do this with a SQL statement?
Edit
The following, of course, does not work.
UPDATE t1
SET type = CASE
WHEN ((SELECT COUNT(*) FROM tg) > 0)
THEN 1
ELSE 0
END
FROM [sampleDB].[dbo].[groups] t1
JOIN (SELECT t2.groupName, t2.flag
FROM [sampleDB].[dbo].[groups] t2) tg ON tg.groupName = t1.groupName
AND tg.flag = 1;
You can try the below -
UPDATE t
SET
type = case when cnt>=1 then 1 else 0 end
FROM
tablename t
INNER JOIN (select group_name, count(case when flag=1 then 1 end) as cnt from tablename
group by group_name)t1
ON t.group_name= t1.group_name
I would use window functions:
with toupdate as (
select g.*, max(flag) over (partition by groupname) as new_flag
from [sampleDB].[dbo].[groups] g
)
update toupdate
set flag = new_flag
where flag <> new_flag;
Note the where clause so only rows where the flag is changing are updated. SQL Server attempts to update row even when no values change, incurring overhead. The where clause saves most of this overhead.
You can simply do it by using a simple JOIN as:
UPDATE D
SET Type = 1
FROM Data D JOIN
(
SELECT GroupName
FROM Data
WHERE Flag = 1
) T ON D.GroupName = T.GroupName;
Here is a db-fiddle
This is the most performant way to solve this problem by using exists statement:
update t1
set type = 1
from table t1
where exists ( select 1
from table t2
where t1.groupname = t2.groupname
and flag = 1
)
This could be other option
;with data
As (
Select count(groupname) groupname
,max(flag) flag
,type
From Tablename
Group by type
Having count(groupname)>1
And max(flag)=1
)
Update c
Set type =1
From data c
I have a table like this.
TABLE-1
id Code
-----------------
1 N188
1 N1Z2
1 N222
2 N189
2 N1Z2
2 N1Z3
3 N188
3 A123
3 B321
4 N188
4 A333
4 B444
I want to select id and code only code has N188.Result should like this:
TABLE-2
id Code
---------------
1 N188
1 N1Z2
1 N222
3 N188
3 A123
3 B321
4 N188
4 A333
4 B444
How can I write sql for this in SQL Server?
Thanks
You can use EXISTS for this:
SELECT id, code
FROM table1 t
WHERE EXISTS (
SELECT 1
FROM table1 t2
WHERE t.id = t2.id
AND t2.Code = 'N188'
)
Condensed SQL Fiddle Demo
Using INNER JOIN
SELECT *
FROM tablename A
JOIN (SELECT id
FROM tablename
WHERE code = 'N188') B
ON a.id = b.id
Here is an alternative method that uses window functions:
select id, code
from (select t.*,
sum(case when code = 'N188' then 1 else 0 end) over (partition by id) as cnt_n188
from table t
) t
where cnt_n188 > 0;
if I have a table with values like this:
ID SUBID FLAG
-----------------
1 1 1
1 2 (null)
2 3 1
2 3 (null)
3 4 1
4 5 1
4 6 (null)
5 7 0
6 8 (null)
7 9 1
and I would like to get all the ID's where 'FLAG' is only set to 1, so in this case the query would return
ID SUBID FLAG
-----------------
3 4 1
7 9 1
How can I achieve this?
try this:
SELECT * FROM flags where flag=1
and ID NOT in( SELECT ID FROM flags where flag !=1 OR flag IS NULL)
I don't have a db2 instance to test on but this might work:
select t1.id, t1.subid, t1.flag
from yourtable t1
inner join
(
select id
from yourtable
group by id
having count(id) = 1
) t2
on t1.id = t2.id
where t1.flag = 1;
I have two tables. Table A has an id column. Table B has an Aid column and a type column. Example data:
A: id
--
1
2
B: Aid | type
----+-----
1 | 1
1 | 1
1 | 3
1 | 1
1 | 4
1 | 5
1 | 4
2 | 2
2 | 4
2 | 3
I want to get all the IDs from table A where there is a certain amount of type 1 and type 3 actions. My query looks like this:
SELECT id
FROM A
WHERE (SELECT COUNT(type)
FROM B
WHERE B.Aid = A.id
AND B.type = 1) = 3
AND (SELECT COUNT(type)
FROM B
WHERE B.Aid = A.id
AND B.type = 3) = 1
so on the data above, just the id 1 should be returned.
Can I combine the 2 subqueries somehow? The goal is to make the query run faster.
Does postgres support CTEs?
WITH counts (Counts, Type, Aid) as (
select count(type), type
from b group by Type, Aid
)
select id
from A
join Counts B1 on b1.Aid = a.id and b1.type = 1
join Counts B3 on b3.Aid = a.id and b3.type = 3
where
b1.counts = 3 and b3.counts = 1
I'd suggest comparing the execution plans, but I suspect it would be similar since everything should get collapsed before execution.
Select ...
From A
Join (
Select B.Id
, Sum ( Case When B.Type = 1 Then 1 Else 0 End ) As Type1Count
, Sum ( Case When B.Type = 3 Then 1 Else 0 End ) As Type3Count
From B
Where B.Type In(1,3)
Group By B.Id
) As Z
On Z.Id = A.Id
Where Z.Type1Count = 3
And Z.Type3Count = 1
This works in TSQL, does it work in Postgres?
SELECT A.ID
FROM A
WHERE A.ID in
(
SELECT AID
FROM B
GROUP BY AID
HAVING
SUM(CASE WHEN Type = 1 THEN 1 ELSE 0 END) = 3
OR SUM(CASE WHEN Type = 3 THEN 1 ELSE 0 END) = 1
)
Another alternative:
SELECT DISTINCT Aid FROM (
SELECT Aid,type,count(*) as n from B
GROUP BY Aid,type, ) as g
WHERE ( g.n=1 AND g.type = 3 )
OR ( g.n=3 AND g.type = 1 )
I doubt this will perform better than your original, though.
You seem to be doing the best strategy: counting only the candidate rows.
Perhaps some redundant prefiltering might help:
SELECT DISTINCT Aid FROM (
SELECT Aid,type,count(*) as n from B
WHERE g.type = 3 OR g.type = 1 -- prefilter
GROUP BY Aid,type, ) as g
WHERE ( g.n=1 AND g.type = 3 )
OR ( g.n=3 AND g.type = 1 )
Consider tables
Table1
id, name
1 xyz
2 abc
3 pqr
Table2
id title
1 Mg1
2 Mg2
3 SG1
Table3
Tb1_id tb2_id count
1 1 3
1 2 3
1 3 4
2 2 1
3 2 2
3 3 2
I want to do query to give result like
id title
1 MG1
2 MG2
3 Two or More Title
MG1 has higher preference if MG1 and count >= 1 then it is given as MG1 title , for others corresponding title is used and for count > 1 as two or more
I think this is what you are going for:
select t3.Tb1_id as id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end as title
from (
select Tb1_id, count(*) as count
from Table3
group by Tb1_id
) cnt
inner join (
select Tb1_id, isnull(SUM(case when t2.title='mg1' then 1 end), 0) as count
from Table3 t3
inner join Table2 t2 on t3.tb2_id = t2.id
group by Tb1_id
) as mg1cnt on cnt.Tb1_id = mg1cnt.Tb1_id
inner join Table3 t3 on cnt.Tb1_id = t3.Tb1_id
inner join Table2 t2 on t3.tb2_id = t2.id
group by t3.Tb1_id,
case
when mg1cnt.count >= 1 then 'MG1'
when cnt.count = 1 then upper(t2.title)
else 'Two or More Titles'
end