Leaf and root record in DB2 - db2

I have a scenario like below.
In a table A the records are below.
col1 col2
---- ----
P1 P2
P2 P3
P3 P4
Now I want a query to get the output as below.
col1 col2
---- ----
P1 P4
Which means P1 is linked to P2 then P2 Linked to P3 and then P3 linked to P4. So we need to get P1 to P4. Can any one suggest how to do this in DB2?

You can use a recursive CTE.
WITH cte (level, col1, col2) AS (
SELECT 1, col1, col2
FROM table_a
WHERE col1='P1'
UNION ALL
SELECT cte.level+1, cte.col1, a.col2
FROM table_a a
INNER JOIN cte ON cte.col2=a.col1
)
SELECT
col1, MAX(col2) as col2, max(level) as level
FROM cte
GROUP BY
col1
;
This SQL Fiddle is for SQL Server 2012, but the syntax is the same for DB2 from what I remember.
EDIT:
Also, you can turn on Hierarchical queries and use the CONNECT BY syntax.
WITH cte AS (
SELECT CONNECT_BY_ROOT col1 as col1, col2 as col2
FROM table_a
START WITH col1='P1'
CONNECT BY PRIOR col2 = col1
)
SELECT col1, MAX(col2) as col2
FROM cte
GROUP BY col1
;
The following SQL Fiddle is for Oracle, but DB2 should be the same.

Related

Inner Joining a large query with itself

Problem:
I need to remove duplicate pairs from the result of a query
(same problem as described here)
So if the result has (A,B), (B,A), (C,A)
I am only interested in (A,B) and (C,A)
The Complication:
Unlike in the linked question, the data is not available in a table to perform an self join and retrieve easily. It is more in the following state
(SELECT C1, C2 from a mind boggling number of joins and unions)
So I can make it a temp table as follows
SELECT T.C1, T.C2
((SELECT C1, C2 from a mind boggling number of joins and unions)) T1
I would like to perform an inner join to remove duplicate pairs as mentioned above
So is there a way to do that in such a scenario
Below query is syntactically wrong, but hopefully it conveys the idea
SELECT A.C1, A.C2
((SELECT C1, C2 from a mind boggling number of joins and unions)) T1 A
INNER JOIN T1 B
ON A.C1 = B.C1 AND
A.C2 < B.C2
I am running SQL Server 2012
here is one way to achieve what you want with CTEs
you can as well use temporary table to store result and use cte1 alone.
with cte
as
(
select col1, col2 from --- your query here.
)
, cte1
as
(
select col1, col2, row_number() over
( partition by (case when col1 >= col2 then col1
else col2
end) ,
(case when col1 <= col2 then col1
else col2
end) order by (select null)
) as rn
from cte
)
select * from cte1 where rn =1

how to count the distinct rows from two tables using joins

I have two tables like
table1 table2
------------ ----------------
col1 col2 col1 col2
I need to count the distinct col1 from table1 if itis matching with table2 col1
note: table2 col1 also distinct
select count(distinct table1.col1)
from table1,table2
where table1.col1=table2.col1
As you select the distinct col of table1, and set the join, the col1 of table2 will also be selected distinctly.

T-SQL find differences

I found Jeff Smith's solution which is displaying differences between two tables:
SELECT MIN(TableName) as TableName, ID, COL1, COL2, COL3 ...
FROM
(
SELECT 'Table A' as TableName, A.ID, A.COL1, A.COL2, A.COL3, ...
FROM A
UNION ALL
SELECT 'Table B' as TableName, B.ID, B.COL1, B.COl2, B.COL3, ...
FROM B
) tmp
GROUP BY ID, COL1, COL2, COL3 ...
HAVING COUNT(*) = 1
ORDER BY ID
In my project I need to compare eg. col1 and col2 only, rest is used for another operations.
I tried to use
HAVING (COUNT(col1) = 1 and COUNT(col2) = 1)
but with no effect.
Could you please ptovide me solution which will do that?
Get the values of COL1 and COL2 in A that do not exist in B using EXCEPT:
SELECT COL1, COL2 FROM A
EXCEPT
SELECT COL1, COL2 FROM B
Use the results as a derived table to join them back to A and get all the columns:
SELECT 'A' AS SRC, A.COL1, A.COL2, A.COL3...
FROM (
SELECT COL1, COL2 FROM A
EXCEPT
SELECT COL1, COL2 FROM B
) AS diff
INNER JOIN A ON diff.COL1 = A.COL1 AND diff.COL2 = A.COL2
Similarly, use EXCEPT to get the values of COL1 and COL2 that exist only in B, and join the resulting set to B obtain complete rows accordingly.
Combine the two sets with UNION ALL:
SELECT 'A' AS SRC, A.COL1, A.COL2, A.COL3...
FROM (
SELECT COL1, COL2 FROM A
EXCEPT
SELECT COL1, COL2 FROM B
) AS diff
INNER JOIN A ON diff.COL1 = A.COL1 AND diff.COL2 = A.COL2
UNION ALL
SELECT 'B' AS SRC, B.COL1, B.COL2, B.COL3...
FROM (
SELECT COL1, COL2 FROM B
EXCEPT
SELECT COL1, COL2 FROM A
) AS diff
INNER JOIN B ON diff.COL1 = B.COL1 AND diff.COL2 = B.COL2
;
You are dropping the columns from the wrong place. You should drop it from the lists of columns instead of from the star:
SELECT MIN(TableName) as TableName, ID, COL1, COL2
FROM
(
SELECT 'Table A' as TableName, A.ID, A.COL1, A.COL2
FROM A
UNION ALL
SELECT 'Table B' as TableName, B.ID, B.COL1, B.COl2
FROM B
) tmp
GROUP BY ID, COL1, COL2
HAVING COUNT(*) = 1
ORDER BY ID
To keep the other columns in the result, you can use MIN (or friends) to keep them:
SELECT MIN(TableName) as TableName, ID, COL1, COL2, MIN(COL3), MIN(COL4), ...
FROM
(
SELECT 'Table A' as TableName, A.ID, A.COL1, A.COL2, A.COL3, A.COL4, ...
FROM A
UNION ALL
SELECT 'Table B' as TableName, B.ID, B.COL1, B.COL2, B.COL3, B.COL4, ...
FROM B
) tmp
GROUP BY ID, COL1, COL2
HAVING COUNT(*) = 1
ORDER BY ID
Note that this doesn't work very well for certain situations. If two rows are identical in the two tables (including IDs), then it will find it as a difference even though it's not. Also, in this version, if you have multiple rows where COL1 and COL2 are the same, then this doesn't work well either. I would join the two tables together for a more robust comparison.

postgres output query within with clause

I'm trying to get the output of queries within the with clause of my final query as csv or some sort of text files. I only have query access, I'm not allowed to create tables for this database. I have a set of queries that do some calculations on a data set, another set of queries that compute on the previous set and yet another that calculates on the final set. I don't want to run all of it as three seperate queries because the results from the first two are actually in the last one.
WITH
Q1 AS(
SELECT col1, col2, col3, col4, col5, col6, col7
FROM table1
),
Q2 AS(
SELECT AVG(col1) as col1Avg, MAX(col1) as col1Max, col2, col3,col4
FROm Q1
GROUP BY col2, col3, col4
)
SELECT
AVG(col1AVG), col3
FROM
Q2
GROUP BY col3
I would like the results from Q1, Q2 and the final select statement as preferably 3 csv files but I could live with all of it in one csv file. Is this possible?
Thanks!
Edit: Just to clarify, the columns from the queries are very different. I'm definitely pulling more columns from my first query than my second. I've edited the above code a bit to make this more clear.
To combine all the results together you'd use UNION ALL, but the number and data types of the columns must match.
select col1, col2, col2
from blah
union all
select col1, col2, col2
from blah2
union all
... etc
You can reference CTE's in there of course ...
with
cte_1 as (
select ... from ...),
cte_2 as (
select ... from ... cte_1),
cte_3 as (
select ... from ... cte_2)
select col1, col2, col2
from cte_1
union all
select col1, col2, col2
from cte_2
union all
select col1, col2, col2
from cte_3
If your final output is a csv then it looks like you have multiple row formats in there -- checksums? If so, in the queries that you union all together you might like to combine all the columns from each query into one string ...
with
cte_1 as (
select ... from ...),
cte_2 as (
select ... from ... cte_1),
cte_3 as (
select ... from ... cte_2)
select col1||','||col2||','||col2
from cte_1
union all
select col1||','||col2
from cte_2
union all
select col1
from cte_3

How to filter sql duplicates?

My question: I want the records without duplicate, in the same table and in multiple tables? How can I proceed to do this in SQL?
Let me explain what I have tried:
Select distinct Col1, col2
from Table
where order id = 143
Output
VolumeAnswer1 AreaAnswer1 heightAnswer1
VolumeAnswer2 AreaAnswer1 heightAnswer2
VolumeAnswer3 AreaAnswer1 heightAnswer2
Expected Output
It shows the duplicate for the second table, but I need the output to be like:
VolumeAnswer1 AreaAnswer1 heightAnswer1
VolumeAnswer2 heightAnswer2
VolumeAnswer3
I need the same scenario for multiple tables, same duplicate I found for joins also. If it cannot be handled in SQL Server, how can we handle it in .Net? I used multiple select but they used to change it in single select. Each and every column should bind in dropdownlist...
Something like this might be a good place to start:
;with cte1 as (
Select col1, cnt1
From (
Select
col1
,row_number() over(Partition by col1 Order by col1) as cnt1
From tbltest) as tbl_sub1
Where cnt1 = 1
), cte2 as (
Select col2, cnt2
From (
Select
col2
,row_number() over(Partition by col2 Order by col2) as cnt2
From tbltest) as tbl_sub2
Where cnt2 = 1
), cte3 as (
Select col3, cnt3
From (
Select
col3
,row_number() over(Partition by col3 Order by col3) as cnt3
From tbltest) as tbl_sub3
Where cnt3 = 1
)
Select
col1, col2, col3
From cte1
full join cte2 on col1 = col2
full join cte3 on col1 = col3
Sql Fiddle showing example: http://sqlfiddle.com/#!3/c9127/1