I am trying to find table links using duplicate column names. Say i have the following tables
T1:
| Prod_ID | Cust_Id | Value |
| P1 | C1 | 1 |
| P2 | C2 | 2 |
| P3 | C3 | 3 |
| P4 | C4 | 4 |
| P5 | C5 | 5 |
T2:
| Prod_ID | Prod_Num |
| P1 | PN1 |
| P2 | PN2 |
| P3 | PN3 |
| P4 | PN4 |
| P5 | PN5 |
I rely on system tables to fetch table information. The data looks like
| tabname | colname |
| T1 | Prod_ID |
| T1 | Cust_Id |
| T1 | Value |
| T2 | Prod_ID |
| T2 | Prod_Num |
| T3 | .... |
If i want to find all tables with columns Prod_ID and Cust_ID, i could do the same using
SELECT tabname, count(*)
FROM syscat.columns
WHERE colname IN ('Prod_ID', 'Cust_Id')
GROUP BY tabname
HAVING count(*) > 1
Now, when i want to find how two columns across tables are linked, the query is getting complex.
For example: To find how Cust_Id and Prod_Num are linked, the expected output would be something like
| tabname | colname |
| T1 | Cust_id |
| T1 | Prod_id |
| T2 | Prod_id |
| T2 | Prod_Num |
Suggesting that Prod_Id is contained in both tables and can be used to map Cust_Id and Prod_num. Is there a script for getting something like above?
I would use self-joins for that.
SELECT c1.tabname, c2.colname joinCol, c3.tabname
FROM syscat.columns c1
JOIN syscat.columns c2 ON c1.tabname = c2.tabname
JOIN syscat.columns c3 ON c3.tabname != c2.tabname and c3.colname = c2.colname
JOIN syscat.columns c4 ON c4.tabname = c3.tabname and c3.colname = c2.colname
WHERE c1.colname = 'Cust_Id' and c4.colname = 'Prod_Num'
The output is the following:
tabname joinCol tabname
---------------------------
T1 Prod_id T2
which means that table t1 is joined with t2 using prod_id (cust_id and prod_num are on the input, therefore there is no need to have them on the output)
demo - it is SQL Server, however, JOIN will work in DB2 as well ;)
Related
i have to create a query that return employees having mutliple territories parent for the same function code :
Table employee_territory_function
employee_id| employee_function_id | territory_id
+----------+-----------------------+-------------+
| 12345 | C1 | t1 |
| 12345 | C1 | t2 |
| 12346 | C2 | t3 |
| 12346 | C2 | t4 |
| 12347 | C4 | t8 |
Table territory
territory_id| territory_parent_id
+-----------+-------------------+
| t1 | P1 |
| t2 | P1 |
| t3 | P2 |
| t4 | P3 |
| t8 | P8 |
the result must be the employee_id 12346 which have multiple parents
my query was :
select * from employee_territory_function tr1 where tr1.employee_id in (
select ee.employee_id from (
select et.employee_id from employee_territory_function et
join territory territory on territory.id = et.territory_id
where et.employee_id in (
select etf.employee_id ,etf.employee_function_id from employee_territory_function etf
group by etf.employee_id ,etf.employee_function_id having count(*)>1)) ee
group by ee.employee_id ,ee.employee_function_id ,ee.territory_parent_id having count(*) =1)
The query takes much time execution with 10k for the couple ( employee , function code )
is there a way to optimize or rewrite the query differently ?
SELECT E.EMPLOYEE_ID,E.EMPLOYEE_FUNCTION_ID
FROM EMPLOYEE AS E
JOIN TERRITORY AS T ON E.TERRITORY_ID=T.TERRITORY_ID
GROUP BY E.EMPLOYEE_ID,E.EMPLOYEE_FUNCTION_ID
HAVING MIN(T.TERRITORY_PARENT_ID)<>MAX(T.TERRITORY_PARENT_ID)
Based on your sample data
I have a one-to-many relation between parent and child tables as follows:
Child table:
+----------+-----------+------------+--------------+
| table_id | parent_id | page_index | other_column |
+----------+-----------+------------+--------------+
| t1 | p1 | 1 | foo |
| t1 | p1 | 2 | bar |
| t2 | p2 | 1 | baz |
+----------+-----------+------------+--------------+
I want to get the final result as follows, i.e. group by parent_id and group by page_index:
+-----------+--------------------------------------------+
| parent_id | pages |
+-----------+--------------------------------------------+
| p1 | [{other_column: foo}, {other_column: bar}] |
| p2 | [{other_column: baz}] |
+-----------+--------------------------------------------+
I tried this query:
SELECT parent_table.parent_id, jsonb_agg(child_table.*) as pages
FROM parent_table
JOIN child_table ON child_table.parent_id = parent_table.parent_id
group by parent_table.parent_id, child_table.page_index
But I got the result containing three rows like:
+-----------+-----------------------+
| parent_id | pages |
+-----------+-----------------------+
| p1 | [{other_column: foo}] |
| p1 | [{other_column: bar}] |
| p2 | [{other_column: baz}] |
+-----------+-----------------------+
So I did another aggregation on top of that using a subquery and grouping by parent_id again as follows:
select sub_q.parent_id, jsonb_agg(sub_q.pages) as pages
from (
SELECT parent_table.parent_id, jsonb_agg(child_table.*) as pages
FROM parent_table
JOIN child_table ON child_table.parent_id = parent_table.parent_id
group by parent_table.parent_id, child_table.page_index
) as sub_q
group by sub_q.parent_id
but I ended up with
+-----------+------------------------------------------------+
| parent_id | pages |
+-----------+------------------------------------------------+
| p1 | [[{other_column: foo}], [{other_column: bar}]] |
| p2 | [{other_column: baz}] |
+-----------+------------------------------------------------+
how do I get the above desired result with each row having a one-dimensional array using the most optimal query?
Would be great if the answer has a db fiddle!
You seem to be overcomplicating this. As far as shown in your sample data, you can get the information you want directly from the child table with simple aggregation:
select
parent_id
jsonb_agg(jsonb_build_object('other_column', other_column) order by page_index) pages
from child_table
group by parent_id
Demo on DB Fiddle:
parent_id | pages
:-------- | :-------------------------------------------------
p1 | [{"other_column": "foo"}, {"other_column": "bar"}]
p2 | [{"other_column": "baz"}]
Table 1
| Customer_ID | Template_ID
---------------------
| C1 | T1 |
| C1 | T2 |
---------------------
Table 2
---------------------
| Template_ID | Product_ID
---------------------
| T1 | P1 |
| T1 | P5 |
| T1 | P5 |
| T2 | P10 |
| T2 | P45 |
Expected Join query result:
------------------------------------------
| Customer_ID | Template_ID | Product_ID
------------------------------------------
| C1 | T1 | P1
| C1 | T1 | P5
| C1 | T2 | P10
| C1 | T2 | P45
.
.
For a template, I want to get only the unique Product_ID like above. Currently my query returns P5 twice like,
.
.
| C1 | T1 | P5
| C1 | T1 | P5
.
.
How can I handle this at the query level?
use distinct
select distinct t1.*,t2.productid
from table1 t1 join table2 t2 on t1.Template_ID =t2.Template_ID
Use DISTINCT to eliminates duplicates. It does not apply to the first column only, but to the whole row.
For example:
select distinct t1.customer_id, t1.template_id, t2.product_id
from t1
join t2 on t2.template_id = t1.template_id
You just have to GROUP BY the field you want to be unique, so Product_ID:
SELECT Customer_ID, Template_ID, Product_ID
FROM table1
JOIN table2 using ( Template_ID )
GROUP BY Product_ID;
Please try this.
SELECT
DISTINCT A.Customer_ID ,A.Template_ID ,B.Product_ID
FROM
table1 AS A
INNER JOIN table2 AS B
ON A.Template_ID = B.Template_ID
I have a question about JOIN.
TABLE A | TABLE B |
-----------------------------------------|
PK | div | PK | div | val |
-----------------------------------------|
A | a | 1 | a | 10 |
B | b | 2 | a | 100 |
C | c | 3 | c | 9 |
------------------| 4 | c | 99 |
-----------------------
There are two tables something like above, and I have been trying to join two tables but I want to see all rows from TABLE A.
Something like
SELECT T1.PK, T1.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div
and I want the result would look like this below.
PK | div | val |
-------------------------
A | a | 10 |
A | a | 100 |
B | null | null |
C | c | 9 |
C | c | 99 |
I have tried all JOINs I know but B doesn't appear because it doesn't exist. Is it possible to show all rows on TABLE A and just show null if it doesn't exists on TABLE B?
Thanks in advance!
If you change your query to
SELECT T1.PK, T2.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div
(Note, that div comes from T2 here.), you'll get exactly the result posted (but maybe in a different order, add an ORDER BY clause if you want a specific order).
Your query as it stands will get you:
PK | div | val |
-------------------------
A | a | 10 |
A | a | 100 |
B | b | null |
C | c | 9 |
C | c | 99 |
(Note, that div is b for the row with the PK of B, not null.)
To get to your resultset, all you need to do is use T2.Div as that is the value that does not exist in the second table:
SELECT T1.PK, T2.div, T2.val
FROM A T1
LEFT OUTER JOIN B T2
ON T1.div = T2.div
Let's take I have a table named 'Table1' having columns and values as below
---------------------------
action | component | type |
---------------------------
1 | 2 | 1 |
2 | 3 | 3 |
3 | 4 | 2 |
---------------------------
and 'Table2' having exactly same structure as 'table1'.
Now I have an other table 'reference' as below
---------------------------
description | id | value |
---------------------------
action | 2 | create|
action | 1 | delete|
action | 3 | update|
component | 2 | c1 |
component | 4 | c2 |
component | 3 | c3 |
type | 2 | t1 |
type | 1 | t2 |
type | 3 | t3 |
---------------------------
Now, I need to move data from 'table1' to 'table2' by referring the values from 'reference' table. My resulting table should look like below.
action | component | type |
---------------------------
delete | c1 | t2 |
create | c3 | t3 |
update | c2 | t1 |
---------------------------
Please help me with the query for the same. Thanks in advance.
You are looking for multiple joins:
select t1a.value as action,
t1c.value as component,
t1t.value as type
from table2 t2 join
table1 t1a
on t2.action = t1a.id and t1a.description = 'action' join
table1 t1c
on t2.component = t1c.id and t1c.description = 'component' join
table1 t1t
on t2.type = t1t.id and t1t.description = 'type';
you can do it like this :
select
(select b.description from reference b where A.action = b.id and b.description = 'action') as action,
(select c.description from reference c where A.action = c.id and c.description = 'component') as component,
(select d.description from reference d where A.action = d.id and d.description = 'type') as type
from table_1 A