I am trying to query a DB with this type of structure
table1
ID -> int
name -> varchar
table2
ID -> int
name1 -> int
name2 -> int
name3 -> int
Where name1 to 3 are table1 IDs. Each line of table2 can have 1 to 3 lines of table1 associated to it and, importantly, the IDs CAN be duplicated (e.g.: name1 and name3 could be the same). The fields are guaranteed to be filled in order (i.e.: if name2 is NULL name3 will also be).
I'm querying the DB like this, in order to get the strings associated to the IDs in the 3 columns:
SELECT t2.ID, t1a.name n1, t1b.name n2, t1c.name n3
FROM table2 t2
LEFT JOIN table1 t1a on t2.name1 = t1a.ID,
LEFT JOIN table1 t1b on t2.name2 = t1b.ID,
LEFT JOIN table1 t1c on t2.name3 = t1c.ID
I'm wondering if there is a way of doing this doing only one LEFT JOIN, or if you could suggest a better table design strategy to achieve this.
Thanks
Select T1.ID
, Min( Case When Z.ColNum = 1 Then Z.Name End ) As n1
, Min( Case When Z.ColNum = 2 Then Z.Name End ) As n2
, Min( Case When Z.ColNum = 3 Then Z.Name End ) As n3
From Table1 As T1
Left Join (
Select ID, 1 As ColNum, name1 As Name
From Table2
Where name1 Is Not Null
Union All
Select Id, 2, name2
From Table2
Where name2 Is Not Null
Union All
Select Id, 3, name3
From Table2
Where name3 Is Not Null
) As Z
On Z.ID = T1.ID
Group By T1.ID
Related
Goal:
Trying to join together two tables
Table structure:
t1:
name | id
t2:
id_a | id_b | id_c | id_d | favorite color
Problem:
I'm trying to find out the favorite color that corresponds to each name, where the t1.id is found in 1 of the 4 id fields in t2. The tricky part is that the non-matching values aren't null, so a coalesce doesn't work.
What I've tried:
Tried a case when statement in the join, but that seems to be creating some endless loop that is never finishing.
Trying a union, but that is creating some unexpected duplication.
Also tried a multi- on condition (like below), but that's not working:
WITH test AS (
SELECT
t1.*
, t2.*
FROM t1
LEFT JOIN t2
ON ( t1.id = t2.id_a
OR t1.id = t2.id_b
OR t1.id = t2.id_c
OR t1.id = t2.id_d
)
)
SELECT COUNT(*) FROM test
;
Here's an example dataset:
WITH names AS(
SELECT
1 as id , 'alfred' as name
UNION ALL SELECT 2, 'becca'
UNION ALL SELECT 3, 'charlie'
UNION ALL SELECT 4, 'dezi'
)
, color AS(
SELECT
1 as id_a, 6 as id_b, 9 as id_c, 7 as id_d, 'green' as fave_color
UNION ALL SELECT 1,2,6,5, 'orange'
UNION ALL SELECT 5,7,9,3, 'blue'
UNION ALL SELECT 9,4,6,8, 'black'
)
SELECT
n.id
, n.name
, c.fave_color
FROM color c
LEFT JOIN names n
ON n.id IN (c.id_a,c.id_b,c.id_c,c.id_d)
GROUP BY 1,2,3
ORDER BY 1,2
;
If I have a MySQL table looking something like this: for example 2014000 is a product pen , there are four types abcd with different prices. and 2014001 is another prodct telephone , also there three types efg with different prices. now I want to get the one product one line with names and values.
id code name value
1 2014000 A 10
2 2014000 B 9
3 2014000 C 11
4 2014000 D 12
5 2014001 E 100
6 2014001 F 110
7 2014001 G 120
respect result:
code name1 value1 name2 value2 name3 value3 name4 value4
----------- --------- --------- --------- --------- ----------- --------- --------- ---------
2014000 A 10 B 9 C 11 D 12
2014001 E 100 F 110 G 120 null null
CREATE TABLE T (ID INT, code INT, NAME CHAR(1), VALUE VARCHAR(10));
INSERT INTO T VALUES(1,2014000,'A','10'), (2,2014000,'B','9'), (3,2014000,'C','11'), (4,2014000,'D','12'), (5,2014001,'E','100'), (6,2014001,'F','110'), (7,2014001,'G','120');
-----the followed only for two rows , if there are more than four rows, how to do it?
SELECT T1.code, T2.name AS name1, T2.value AS value1, T3.name AS name2, T3.value AS value2 FROM( SELECT code,MIN(ID) AS ID1,CASE COUNT(code) WHEN 1 THEN NULL ELSE MAX(ID) END AS ID2 FROM T GROUP BY code ) T1 LEFT JOIN T T2 ON T1.ID1 = T2.ID LEFT JOIN T T3 ON T1.ID2 = T3.ID
SELECT t.code
, t1.name name1
, t1.value value1
, t2.name name2
, t2.value value2
, t3.name name3
, t3.value value3
, t4.name name4
, t4.value value4
FROM ( SELECT code
, group_concat(ID) ids
FROM T
GROUP BY code
) t
LEFT JOIN T t1
ON find_in_set(t1.ID,t.ids)=1
LEFT JOIN T t2
ON find_in_set(t2.ID,t.ids)=2
LEFT JOIN T t3
ON find_in_set(t3.ID,t.ids)=3
LEFT JOIN T t4
ON find_in_set(t4.ID,t.ids)=4
I have 3 tables as follows
Table1
Id Name
1 abcd
2 bcd
3 dabc
Table2
Id2 Name2
2 xyz
3 def
4 mno
Table3
Id Id2 Value
1 4 1
2 3 1
3 4 1
Now,
From table1 : I have to select all Id where Name is %abc%
From table2: I have to select Id2 where Name2 is "mno"
From Table3: I have to change value to 0 from 1 where Id's value are from Table1 and Id2 is from Table2.
Table 1:
select Id from Table1 where Name like '%abc%'
Table2 :
select Id2 from Table2 where Name2 = "mno"
Table 3:
update Table3 set Value = 0 where Id in() and Id2=
But, I dont know how to make it 1 single query. Can anyone please guide me up ?
Refer to: prior stack article
You've not explained how T1 relates to T2, So I have assumed a cross join.
Whenever you have a record in T1 with name like '%abc%' (1,3) in your data..
and whenever you have a record in T2 with a name equal to 'mno' 4 then you want the value in table 3 to be 0
so the select we generate should produce
1,4
3,4
and when we inner join this back to table 3 it only selects
Id Id2 Value
1 4 1
3 4 1
Now we generate an update based on this select as outlined in the link provided above...
UPDATE table3
INNER JOIN (
SSELECT t1.ID t1ID, t2.id t2ID
FROM table1 t1
CROSS JOIN table2
WHERE t1.name like '%abc%'
and t2.name like = 'mno') B
on B.t1ID = t3.Id
and B.t2ID = T3.ID2
SET value = 0
Giving us a result of
Id Id2 Value
1 4 0
2 3 1
3 4 0
if we select * from table3
update t3
set t3.Value = 0
from Table3 t3
inner join Table1 t1
on t3.Id = t1.Id
inner join Table2 t2
on t3.Id2 = t2.Id2
where t1.Name like '%abc%' and t2.Name2 = 'mno'
OR
update Table3
set value = 0
where Id in (select Id from Table1 where Name like '%abc%')
and Id2 in (select Id2 from Table2 where Name2 = 'mno')
You should think about UPDATE ... WHERE EXISTS as follows:
update Table3 set Value = 0
WHERE EXISTS (SELECT 1 FROM Table1 where Name LIKE '%abc%' AND Table1.Id=Table3.Id )
AND EXISTS (SELECT 1 FROM Table2 where Name2 = "mno" AND Table2.Id2=Table3.Id2)
Having a (MySQL) audit table containing rows that are similar, is it possible to view only those columns that have different values?
For example, a table containing four columns where column key is primary key, and column id is the identifier to match rows:
key id col1 col2
1 123 B C
2 123 A C
3 456 B C
4 789 B A
5 789 B B
6 987 A C
In the example above I need the query to return only row 1, 2, 4, and 5 as they have matching id, and differing values in col1 and col2, ie B,A and B,A.
key id col1 col2
1 123 B
2 123 A
4 789 A
5 789 B
I know it might not be very efficient solution, but gives what you want. HERE try this:
SELECT A.ID, (CASE A.col1 WHEN B.col1 THEN NULL ELSE B.col1 END), (CASE A.col2 WHEN B.col2 THEN NULL ELSE B.col2 END) FROM tblName A
FULL OUTER JOIN tblName B
ON
A.ID=B.ID
WHERE
(A.col1=B.col1 AND A.Col2<>B.Col2)
OR
(A.col2<>B.col2 AND A.Col1=B.Col1)
INNER JOIN should give same result
This is a bit contrived, in the sense that adding more rows will give very different results - but anyway...
SELECT x.my_key
, x.id
, IF(y.col1=x.col1,'',x.col1) col1
, IF(y.col2=x.col2,'',x.col2) col2
FROM my_table x
JOIN my_table y
ON y.id = x.id
AND y.my_key <> x.my_key
WHERE (y.col1 <> x.col1 OR y.col2 <> x.col2)
ORDER
BY my_key;
Thanks for all responses which guided me.
Using your suggestions I made the sql like this:
SELECT
T1.KEY,
T1.ID,
CASE T2.COL1_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL1 END AS COL1,
CASE T2.COL2_DISTINCT_VALUES WHEN 1 THEN NULL ELSE T1.COL2 END AS COL2
FROM
TAB1 T1
INNER JOIN
(
SELECT
ID,
COUNT(DISTINCT COL1) AS COL1_DISTINCT_VALUES,
COUNT(DISTINCT COL2) AS COL2_DISTINCT_VALUES
FROM
TAB1
GROUP BY
ID
) T2
ON T1.ID=T2.ID
WHERE
T2.COL1_DISTINCT_VALUES > 1
OR T2.COL2_DISTINCT_VALUES > 1
ORDER BY
KEY,ID;
I learned the hard way that Access does not allow you to do full outer joins, and while reading on how to simulate one, I have begun to understand how to do so, but am having issues trying to apply this to more than just two tables.
Is it as simple as doing the following?
SELECT * FROM table1
LEFT JOIN table2 ON table1.field = table2.field
LEFT JOIN table3 ON table1.field = table3.field
UNION
SELECT * FROM table1
RIGHT JOIN table2 ON table1.field = table2.field
RIGHT JOIN table3 ON table1.field = table3.field
A quick search of the web revealed that the subject of simulating a FULL OUTER JOIN ("FOJ") has been discussed many times on Stack Overflow and elsewhere, but the answers all seem to limit themselves to the case with only two tables. I suspected it was because a FOJ on three or more tables was
not a very common occurrence, and
potentially quite messy.
Still, I thought I'd give it a go, and here's what I came up with:
The technique most commonly mentioned for simulating a FOJ on two tables is to UNION ALL the three possible cases:
In_Table2 In_Table1
--------- ---------
false true
true false
true true
or, substituting true=1 and false=0
In_Table2 In_Table1
--------- ---------
0 1
1 0
1 1
That looks like a two-bit integer with three possible non-zero values, and the SQL to extract those would be of the form
Table2 RIGHT JOIN Table1 WHERE Table2.something IS NULL
UNION ALL
Table2 LEFT JOIN Table1 WHERE Table1.something IS NULL
UNION ALL
Table2 INNER JOIN Table1
The state table for the case with three tables would therefore look like a three-bit integer with seven possible non-zero values
In_Table3 In_Table2 In_Table1
--------- --------- ---------
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
I wanted to do the join on an integer value, so I just assigned them sequentially for each of the seven rows
Table3 Table2 Table1
------ ------ ------
1
2
3 3
4
5 5
6 6
7 7 7
so my test tables were
[Table1]
n txt
- ----
1 t1_1
3 t1_3
5 t1_5
7 t1_7
[Table2]
n txt
- ----
2 t2_2
3 t2_3
6 t2_6
7 t2_7
[Table3]
n txt
- ----
4 t3_4
5 t3_5
6 t3_6
7 t3_7
I created a saved query in Access named [foj12] to perform the FOJ between [Table1] and [Table2]
SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
FROM
Table1 t1
INNER JOIN
Table2 t2
ON t1.n = t2.n
UNION ALL
SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
FROM
Table1 t1
LEFT JOIN
Table2 t2
ON t1.n = t2.n
WHERE t2.n IS NULL
UNION ALL
SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
FROM
Table1 t1
RIGHT JOIN
Table2 t2
ON t1.n = t2.n
WHERE t1.n IS NULL
It returns
t1_n t1_txt t2_n t2_txt
---- ------ ---- ------
1 t1_1
2 t2_2
3 t1_3 3 t2_3
5 t1_5
6 t2_6
7 t1_7 7 t2_7
Then I started working through the cases involving [Table3]. They were as follows, and correspond to the "unioned" queries in the SQL statement below.
Table3 matches both Table1 and Table2 (n=7)
Table3 matches Table1 but not Table2 (n=5)
Table3 matches Table2 but not Table1 (n=6)
rows in Table3 that don't match anything in Table1 or Table2 (n=4)
rows in FOJ(Table1,Table2) that have nothing in common with Table3 (n=1,2,3)
SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
FROM
Table3 t3
INNER JOIN
foj12 f
ON t3.n = f.t1_n AND t3.n = f.t2_n
UNION ALL
SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
FROM
Table3 t3
INNER JOIN
foj12 f
ON t3.n = f.t1_n
WHERE f.t2_n IS NULL
UNION ALL
SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
FROM
Table3 t3
INNER JOIN
foj12 f
ON t3.n = f.t2_n
WHERE f.t1_n IS NULL
UNION ALL
SELECT NULL, NULL, NULL, NULL, t3.n AS t3_n, t3.txt AS t3_txt
FROM
Table3 t3
WHERE t3.n NOT IN (SELECT t1_n FROM foj12 WHERE t1_n IS NOT NULL)
AND t3.n NOT IN (SELECT t2_n FROM foj12 WHERE t2_n IS NOT NULL)
UNION ALL
SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, NULL, NULL
FROM foj12 f
WHERE
(f.t1_n NOT IN (SELECT n FROM Table3) AND f.t2_n NOT IN (SELECT n FROM Table3))
OR
(f.t1_n NOT IN (SELECT n FROM Table3) AND f.t2_n IS NULL)
OR
(f.t1_n IS NULL AND f.t2_n NOT IN (SELECT n FROM Table3))
ORDER BY 5, 3, 1
That little beauty returns
t1_n t1_txt t2_n t2_txt t3_n t3_txt
---- ------ ---- ------ ---- ------
1 t1_1
2 t2_2
3 t1_3 3 t2_3
4 t3_4
5 t1_5 5 t3_5
6 t2_6 6 t3_6
7 t1_7 7 t2_7 7 t3_7
(Needless to say I'm not interested in adding a fourth table! :)
Comments welcome.