I want to pick the IDs when the two conditions are met
Col2 of every ID should have 1 and
the consecutive row of same ID should be 2
it does not matter where 1 is but 2 must be the consecutive row after 1.
IDs
Col2
97654
1
97854
2
97854
3
97854
4
97854
5
76543
1
76543
3
76543
2
12345
2
12345
3
12345
4
34567
3
34567
1
34567
2
output
IDs
97854
34567
I tried to use this code but here it outputs all the IDs
SELECT *
from (SELECT IDs, Col2 FROM table_name where Col2 = 1)a
left outer join (SELECT IDs, Col2 FROM table_name where Col2 = 2)b
on a.IDs=b.IDs
Help is appreciated.
To do what you are asking for you should use window functions. Make it row_number or lead ones.
One option is:
SELECT t0.IDs
from (select *, ROW_NUMBER OVER (PARTITION BY IDs) as rn from table_name) t0
left join (select *, ROW_NUMBER OVER (PARTITION BY IDs) as rn from table_name) t1 on (t0.IDs = t1.IDs AND t0.rn + 1 = t1.rn)
where t0.Col2=1 and t1.Col2=2
You can join the table with itself. Each instance picks row #1 and row #2 respectively, and the join ensures both are present.
For example:
select t.ids
from t
join t b on b.ids = t.ids
where t.col2 = 1 and b.col2 = 2
Related
I am using StandardSQL in BigQuery and have 7 tables with 10 to 75 columns each and thousands of rows. For simplicity I will only use the relevant tables and columns for what I am trying to accomplish.
Table 1
Item
Desc
12341
abcd
23451
bcda
34561
cdab
45671
dabc
Table 2
SubItem
Location
ON_OFF
OnHand
OnOrder
12345
1
ON
3
5
12345
2
ON
4
2
12345
3
ON
2
4
12346
1
ON
7
7
12346
2
ON
1
4
12346
3
ON
8
7
23451
1
OFF
1
1
23451
2
OFF
3
2
34567
1
ON
6
0
34567
2
ON
1
5
34568
1
ON
2
0
34568
2
ON
3
10
45671
2
ON
5
1
Table 3
Item
SubItem
12341
12346
23451
23451
34561
34567
34561
34568
Current Result
Item
Desc
ON_OFF
OH
OO
12341
abcd
ON
9
11
12341
abcd
ON
16
18
23451
bcda
OFF
4
3
34561
cdab
ON
7
5
34561
cdab
ON
5
10
45671
dabc
ON
5
1
Desired Result
Item
Desc
ON_OFF
OH
OO
12341
abcd
ON
9
18
23451
bcda
OFF
4
3
34561
cdab
ON
5
5
45671
dabc
ON
5
1
I am looking for the Minimum OH and Minimum OO Value for each item and as in the case of Item 45671, that does not correspond with the same SubItem number.
Current code providing me with the Current Result table is:
Select
Table1.Item,
Table1.Desc,
Table2.ON_OFF,
Table2.OH,
Table2.OO
From Table1
Left Join Table3
On Table1.Item = Table3.Item
Left Join
(Select SubItem, ON_OFF, Sum(OnHand) As OH, Sum(OnOrder) As OO
From Table 2
Group by 1,2)
ON Table3.SubItem = Table2.SubItem;
Looking for ideas as I am still fairly new to SQL and the current actual code ties 7 tables with various joins to build a final table with 45 columns and thousands of rows. I have looked at using RowNumber() and Partition By, but I am not sure where it would go. Was also thinking separating the OO and OH into two joins might help.
Any suggestions welcome! Thank you!
Looking at your sample data, It seems that You can use group by and aggregate function min as follows:
Select Table1.Item,
Table1.Desc,
Table2.ON_OFF,
Min(Table2.OH),
Min(Table2.OO)
From Table1
Left Join Table3
On Table1.Item = Table3.Item
Left Join (Select SubItem,
ON_OFF,
Sum(OnHand) As OH,
Sum(OnOrder) As OO
From Table2
Group by 1,2) Table2
ON Table3.SubItem = Table2.SubItem
Group by Table1.Item, Table1.Desc, Table2.ON_OFF;
I worked with it after getting some much needed sleep...
I came up with the below and it is working!
SELECT T1.Item,
T1.Desc,
T3_1.ONOFF,
T3_1.OH,
T3_2.OO
FROM Table1 T1
Left Join
(Select Item, SubItem,T2_1.O_O as ONOFF, T2_1.OH1 as OH,
ROW_NUMBER() OVER(PARTITION BY Item ORDER BY T2_1.OH1) as rn
FROM T2_1
Left Join
(Select SubItem, SUM(IFNULL(OnHand,0)) AS OH1,
FROM Table2
GROUP BY 1) T2_1
ON T2_1.SubItem = T3_1.SubItem) T3_1
On T1.Item = T3_1.Item
Left Join
(Select Item, SubItem, T2_2.OO1 as OO,
ROW_NUMBER() OVER(PARTITION BY Item ORDER BY T2_2.OO1) as rn2
FROM T2_2
Left Join
(Select SubItem, SUM(IFNULL(OnOrder,0)) AS OO1,
FROM Table2
GROUP BY 1) T2_2
ON T2_2.SubItem = T3_2.SubItem) T3_2
On T1.Item = T3_2.Item
Where rn = 1 and rn2 = 1;
Thanks!
I have table with following schema and contains records-
id parent_id active
1 NULL Y
2 1 Y
3 1 N
4 NULL Y
5 4 N
6 NULL N
7 6 N
I need to write a SQL for following use case:
Need to find all records whose active not equals to Y and whose parent_id active equals to Y.
Example output of above should be as follows:
output should be-
id parent_id active
3 1 N
5 4 N
You could do it using self join as below:
SELECT *
FROM mytab t1 INNER JOIN mytab t2
ON t1.id = t2.parent_id
WHERE t1.active != 'Y'
AND t2.active = 'Y'
You can do this using self-join as following:
select t1.id,t1.parent_id,t1.active
from test t1 inner join test t2 on t1.parent_id=t2.id
where t1.active <> 'Y' and t2.active='Y';
Results can be seen here:
DB Fiddle Demo
use subquery 1st take all the id's who have active=Y then check with parent_id and active column
select * from tbale_name where
parent_id in (
select id from table_name where active='Y'
) and active='N'
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=4a450a50a2ea6c3f4e1a19e2657ae35d
id parent_id active
3 1 N
5 4 N
I have a three tables
Table 1
Id Department
1 A
2 B
3 C
4 D
Table 2
Id DepartId Name
1 1 ABC
2 1 DEF
3 1 ASD
4 2 FGH
5 2 HJK
6 3 ZXC
Table 3
Id Depart Area
1 A pp
2 B
3 C nn
4 D oo
I need the result
Id Depart Name Area
1 A ABC pp
2 B FGH Null
3 C ZXC nn
4 D NULL oo
I need one matching entry from table 2 and table 3 to corresponding entry in the table 1
Do a left join to also get t1 rows without any reference in the t2 table. GROUP BY to get only 1 row per Department.
select t1.id, t1.Department, min(t2.Name)
from t1
left join t2 on t1.id = t2.DepartId
group by t1.id, t1.Department
I think I would do this with a correlated subquery:
select t1.*,
(select t2.name
from t2
where t1.id = t2.DepartId and rownum = 1
) as t2name
from t1;
This saves the overhead of an aggregation. An index on t2(DepartId, name) is optimal for this query.
by the way not the answer to your specific question but if instead of just one you want all the names you can use listagg
SELECT t1.id,
department,
LISTAGG (name, ',') WITHIN GROUP (ORDER BY name) names
FROM t1, t2
WHERE t1.id = t2.departId(+)
GROUP BY t1.id, department
ORDER BY 1
ID Department Names
1 A ABC,ASD,DEF
2 B FGH, HJK
3 C ZXC
4 D
EXPLAINATION
Imagine that I have 2 tables. FormFields where are stored column names as values, which should be pivoted and second table FilledValues with user's filled values with FormFieldId provided.
PROBLEM
As you see (below in SAMPLE section) in FormFields table I have duplicate names, but different ID's. I need to make that after joining tables, all values from FilledValues table will be assiged to column names, not to Id's.
What I need better you will see in OUTPUT section below.
SAMPLE DATA
FormFields
ID Name GroupId
1 col1 1
2 col2 1
3 col3 1
4 col1 2
5 col2 2
6 col3 2
FilledValues
ID Name FormFieldId GroupID
1 a 2 1
2 b 3 1
3 c 1 1
4 d 4 2
5 e 6 2
6 f 5 2
OUTPUT FOR NOW
col1 col2 col3
c a b -- As you see It returning only values for FormFieldId 1 2 3
-- d, e, f are lost that because It have duplicate col names, but different id's
DESIRED OUTPUT
col1 col2 col3
c a b
e f d
QUERY
SELECT * FROM
(
SELECT FF.Name AS NamePiv,
FV.Name AS Val1
FROM FormFields FF
JOIN FilledValues FV ON FF.Id = FV.FormFieldId
) x
PIVOT
(
MIN(Val1)
FOR NamePiv IN ([col1],[col2],[col3])
) piv
SQL FIDDLE
How can I produce the OUTPUT with the multiple rows?
Since you are using PIVOT the data is being aggregated so you only return one value for each column being grouped. You don't have any columns in your subquery that are unique and being used in the grouping aspect of PIVOT to return multiple rows. In order to do this you need some value. If you have a column with a unique value for each "group" then you would use that or you can use a windowing function like row_number().
row_number() will create a sequenced number for each FF.Name meaning if you have 2 col1 you will generate a 1 for a row and a 2 for another row. Once this is included in your subquery, you now have a unique value that is used when aggregating your data and you will return multiple rows:
SELECT [col1],[col2],[col3]
FROM
(
SELECT
FF.Name AS NamePiv,
FV.Name AS Val1,
rn = row_number() over(partition by ff.Name order by fv.Id)
FROM FormFields FF
JOIN FilledValues FV ON FF.Id = FV.FormFieldId
) x
PIVOT
(
MIN(Val1)
FOR NamePiv IN ([col1],[col2],[col3])
) piv;
See SQL Fiddle with Demo. The output is:
| col1 | col2 | col3 |
|------|------|------|
| c | a | b |
| e | f | d |
Just adding GroupId in Pivot source query will fix your problem
SELECT * FROM (
SELECT FF.Name AS NamePiv,
FV.Name AS Val1,
ff.groupid
FROM FormFields FF
JOIN FilledValues FV ON FF.Id = FV.FormFieldId
) x
PIVOT
(
MIN(Val1)
FOR NamePiv IN ([col1],[col2],[col3])
) piv
SQLFIDDLE DEMO
I would be inclined to do this with conditional aggregation:
select max(case when formfieldid % 3 = 1 then name end) as col1,
max(case when formfieldid % 3 = 2 then name end) as col2,
max(case when formfieldid % 3 = 0 then name end) as col3
from FilledValues
group by GroupID;
It is unclear what the rule is for assigning a value to a column. This uses the remainder, which works for your input data.
id idtest result
1 1 2
1 2 1
1 3 2
2 1 2
2 2 1
2 3 1
3 1 1
3 2 2
3 3 1
Would like to get all the rows with the same IDs that matches the condition.
For example: get all the rows with the same id where (idTest=2 and result=1) and (idTest=3 and result=2)
result:
id idtest result
1 1 2
1 2 1
1 3 2
What would be the query???
Thanks!
Do you mean this?
SELECT * FROM table WHERE id = 1 and (result = 1 OR result = 2)
How about his:
SELECT *
FROM table WHERE (idTest = 2 OR idTest = 3) AND (result=1 OR result=2)
ID test res
1 1 2
1 2 1
1 3 2
2 1 1
2 2 2
2 3 2
3 1 1
3 2 2
3 3 1
Sorry. This would be my table. and Would like to get all the rows with the same IDs that matches the condition. For example: get all the rows with the same id where (test=2 and res=1) and (test=3 and res=2)
Result:
ID test res
1 1 2
1 2 1
1 3 2
What would be the query in order to get the three rows ?? Thanks!
You can use EXISTS:
SELECT id, idTest, result
FROM dbo.TableName t
WHERE EXISTS
(
SELECT 1 FROM dbo.TableName t2
WHERE t.id = t2.id
AND(
( t2.idTest=2 AND t2.result=1 )
OR
( t2.idTest=3 AND t2.result=2 )
)
)
Demo
Update: result is different:
id idTest result
1 1 2
1 2 1 <-- satisfies your condition
1 3 2 <-- satisfies your condition
2 1 2
2 2 1 <-- satisfies your condition
2 3 1
So either my understanding was incorrect or your expected result. I have also all ID=2 because the second id-2 row matches the condition.
You seem to want all rows for id's that have rows with that particular combination. What about:
with ids as (
select id
from mytable
where (idTest=2 and result=1) or (idTest=3 and result=2)
group by id
having count(id) = 2
)
select mytable.* from mytable
inner join ids
on ids.id = mytable.id
This gets a list of id's where both conditions apply, and then gets all rows for those id's.
SqlFiddle
SELECT *
FROM table t1
WHERE EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 2 AND result = 1)
AND EXISTS (SELECT 1 FROM table WHERE id = t1.id AND idtest = 3 AND result = 2)
Just keep adding more AND EXISTS if you need more
Or you can use IN if it makes more sense to you
SELECT *
FROM table
WHERE id IN (SELECT id from table where idtest = 2 and result = 1)
AND id IN (SELECT id from table where idtest = 3 and result = 2)
do you need a method that treats the condition(s) in a generic way, like if they're values in another table? Or do you only need a way to pull results of two independent conditions?
If the latter, then this should work:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=2 AND RESULT=1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=3 AND RESULT=2) cond2 ON
cond1.id = cond2.id
otherwise, if your conditions are generic and stored in a table, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 1 AND idTest=c.idTestVal AND result=c.resultVal) cond1 INNER JOIN
(SELECT id
FROM tbl FULL OUTER JOIN conditions c
WHERE c.isUseMe = 1 AND c.SEQ = 2 AND idTest=c.idTestVal AND result=c.resultVal) cond2 ON
cond1.id = cond2.id
if the 4 values are passed in as parameters, you'd need something like:
SELECT
id
FROM
(SELECT id
FROM tbl
WHERE idTest=#idTestVal1 AND result=#resultVal1) cond1 INNER JOIN
(SELECT id
FROM tbl
WHERE idTest=#idTestVal2 AND result=#resultVal2) cond2 ON
cond1.id = cond2.id