Mysql join on null - mysql

I have 2 tables, each with 3 columns to join with.
table A
c1 c2 c3
10 NULL NULL
10 NULL 1
10 1 NULL
table B
c1 c2 c3
10 NULL NULL
10 NULL 1
10 1 NULL
I would like to join them so that NULL = NULL, so
SELECT * FROM a JOIN b ON a.c1 = b.c1 AND a.c2 = b.c2 AND a.c3 = b.c3
I would like it to join on NULL should match NULL. So that in the end I'm getting the 3 records:
table A+B
c1 c2 c3 c1 c2 c3
10 NULL NULL 10 NULL NULL
10 NULL 1 10 NULL 1
10 1 NULL 10 1 NULL
is this possible somehow? I have tried also with IFNULL but did'n get the results what I expect. I would be grateful if you could point me to the right direction. Many thanks!

Use the NULL-safe equality operator:
SELECT *
FROM a JOIN
b
ON a.c1 <=> b.c1 AND a.c2 <=> b.c2 AND a.c3 <=> b.c3;
However, with your sample data, a join on the first column is sufficient:
SELECT *
FROM a JOIN
b
ON a.c1 = b.c1 ;

Related

MySQL ORDER BY field created by GROUP_CONCAT()

Input two table, TABLE_A and TABLE_B
TABLE_A TABLE_B
A_ID | A A_ID | B
1 | a 1 | b
2 | a1 1 | b1
3 | a2 2 | b2
Expecting Output TABLE C
TABLE_C
A_ID | A | C
3 | a2 | NULL <--- NULL if no matched A_ID in TABLE B
1 | a | b,b1 <--- Concat all rows in TABLE B with ','
2 | a1 | b2
Following code can almost give the above TABLE_C except I want to sort field C with NULL first then DESC. ORDER BY C IS NULL DESC does not seems to work. Note that if C is NULL TABLE_C will order by A_ID regardless the value in field C.
SELECT
A1.A_ID,
A1.A,
GROUP_CONCAT(B1.B SEPARATOR ',') as 'C'
FROM `TABLE_A` A1
LEFT JOIN `TABLE_B` B1
ON A1.A_ID=B1.A_ID
GROUP BY A1.A_ID, A1.A;
Following SQL gives error.
SELECT
A1.A_ID,
A1.A,
GROUP_CONCAT(B1.B SEPARATOR ',') as 'C'
FROM `TABLE_A` A1
LEFT JOIN `TABLE_B` B1
ON A1.A_ID=B1.A_ID
GROUP BY A1.A_ID, A1.A
ORDER BY C IS NULL DESC, A1.A_ID; <--- Order by C with NULL failed.
Reference 'C' not supported (reference to group function)
To ORDER BY Null values first and then by A1.A_ID use:
SELECT A1.A_ID, A1.A, GROUP_CONCAT(B1.B SEPARATOR ',') as C
FROM `TABLE_A` A1
LEFT JOIN `TABLE_B` B1 ON A1.A_ID=B1.A_ID
GROUP BY A1.A_ID, A1.A
ORDER BY (CASE WHEN GROUP_CONCAT(B1.B SEPARATOR ',') IS NULL then GROUP_CONCAT(B1.B SEPARATOR ',') ELSE A1.A_ID END) ;
and regarding the error Reference 'C' not supported (reference to group function) you should be ordering by 'C' ie
ORDER BY 'C' IS NULL DESC, A1.A_ID;
and not ORDER BY C IS NULL DESC, A1.A_ID;
You can not use Is Null in order by
SELECT
A1.A_ID,
A1.A,
GROUP_CONCAT(B1.B SEPARATOR ',') as 'C'
FROM `TABLE_A` A1
LEFT JOIN `TABLE_B` B1
ON A1.A_ID=B1.A_ID
GROUP BY A1.A_ID, A1.A
ORDER BY C, A1.A_ID DESC

mysql Return duplicates and exclude lowest id

I am trying list all the rows from my query that will return all the duplicates next to each other so I can then grab their id's but i also want to exclude the id with the lowest number from the results. How can I go about doing that with my query.
My Query
SELECT
a.tail_number,
min(a.id),
b.aircraft_id
from aircraft a
left join jobs b on a.id = b.aircraft_id
where
a.active = 1 and b.aircraft_id is null
group by a.tail_number having count(*) > 1
The current Output
tail_number min(a.id) aircraft_id tail_count
125TH 4429 NULL 7
362FX 4223 NULL 7
439FL 4221 NULL 7
453FX 4220 NULL 7
455FX 4259 NULL 7
The output im trying to achieve
tail_number min(a.id) aircraft_id tail_count
125TH 4429 NULL 1
125TH 4430 NULL 1
125TH 4431 NULL 1
125TH 4432 NULL 1
362FX 4223 NULL 1
362FX 4224 NULL 1
362FX 4225 NULL 1
362FX 4226 NULL 1
Join with a subquery that gets the lowest ID for each tail number, and then exlude that from the results in the ON condition.
SELECT a.tail_number, a.id
FROM aircraft AS a
JOIN (SELECT tail_number, MIN(id) AS minid
FROM aircraft
WHERE active = 1
GROUP BY tail_number
HAVING COUNT(*) > 1) AS m ON a.tail_number = m.tail_number AND a.id != m.minid
LEFT JOIN jobs AS j ON a.id = j.aircraft_id
WHERE j.aircraft_id IS NULL
ORDER BY a.tail_number, a.id
I've moved the checks for active = 1 and COUNT(*) > 1 into the subquery as well, since there's no longer any grouping in the main query.

MYSQL get the first value in JOIN query

I have 3 tables: A, B and C.
A has AID, B has AID and BID, and C has BID Value and Date.
I need to create a query that returns me AID and the first (according to date) Value from C.
WHAT I've tried:
SELECT A.AID, Value FROM A INNER JOIN B on A.AID = B.BID
INNER JOIN C ON C.BID = B.BID GROUP BY A.AID
It gives me the last Value and not the first.
Data example:
A:
AID:
1
2
3
B:
AID BID
1 1
1 2
2 3
3 4
3 5
3 6
C:
BID Value Date
1 15 1.1.1970
1 422 1.1.1992
2 945 1.1.1975
3 149 1.1.1994
3 147 1.1.2015
4 110 1.1.2004
5 142 1.1.2005
The output should be:
AID Value
1 15
2 149
3 110
If you do not have too many records with the same value and value doesn't have any commas, then the group_concat()/substring_index() trick is probably the easiest way:
select b.aid,
substring_index(group_concat(c.value order by c.date desc), ',' 1) as first_value
from c join
b
on c.bid = b.bid
group by b.aid;
Larger amounts of data require a more complicated query. Something like:
select b.aid, c.value
from c join
b
on c.bid = b.bid
where c.date = (select min(c2.date)
from c2 join
b2
on c2.bid = b2.bid
where b2.aid = b.aid
);
To restrict C to just those rows with the latest (minimum) date you need a subquery that will produce the minimum date, then use that to limit the rows from C
SELECT
A.AID
, C.Value
FROM A
INNER JOIN B ON A.AID = B.BID
INNER JOIN C ON b.bid = c.bid
INNER JOIN (
SELECT
bid
, MIN(date) AS mindate
FROM c
GROUP BY
bid
) AS m ON c.bid = m.bid
AND c.date = m.mindate
DROP TABLE IF EXISTS b;
CREATE TABLE b
(aid INT NOT NULL
,bid INT NOT NULL
,PRIMARY KEY(aid,bid)
);
INSERT INTO b VALUES
(1 ,1),
(1 ,2),
(2 ,3),
(3 ,4),
(3 ,5),
(3 ,6);
DROP TABLE IF EXISTS c;
CREATE TABLE c
(bid INT NOT NULL
,value INT NOT NULL
,date DATE
,PRIMARY KEY(bid,date)
);
INSERT INTO c VALUES
(1 ,15 ,'1970-01-01'),
(1 ,422 ,'1992-01-01'),
(2 ,945 ,'1975-01-01'),
(3 ,149 ,'1994-01-01'),
(3 ,147 ,'2015-01-01'),
(4 ,110 ,'2004-01-01'),
(5 ,142 ,'2005-01-01');
SELECT x.aid
, y.value
FROM b x
JOIN c y
ON y.bid = x.bid
JOIN
( SELECT b.aid
, MIN(c.date) min_date
FROM b
JOIN c
ON c.bid = b.bid
GROUP
BY b.aid
) z
ON z.min_date = y.date
AND z.aid = x.aid;
+-----+-------+
| aid | value |
+-----+-------+
| 1 | 15 |
| 2 | 149 |
| 3 | 110 |
+-----+-------+

Select data from MySQL tables

I have 2 tables called table_one and table_two, with the following properties:
Both of them have one common column called column_id.
The values of table_one.column_id are unique, whereas the values of table_two.column_id are not.
table_two has two extra columns called ts_one and ts_two. ts_one is not null, but ts_two may be null. Only one row per table_two.column_id permits the ts_two value to be null.
Not all values from table_one.column_id may be presented in table_two.column_id.
For example:
table_one
column_id
1
2
3
4
5
table_two
column_id ts_one ts_two
2 2014-10-01 null
3 2014-10-02 2014-10-03
3 2014-10-05 null
4 2014-10-01 2014-10-05
I need to get all id from table_one.column_id, where:
id in table_one.column_id and not in table_two.column_id(1, 5 satisfy that)
id in table_one.column_id and in table_two.column_id where ts_two is not null and there is no another rows with same id where ts_two with null value - (only 4 satisfy).
Both conditions should be taken into account. The results should include 1, 4, and 5.
You can do this with a single join and an aggregate...
SELECT t1.column_id FROM table_one AS t1
LEFT JOIN (
SELECT column_id, (COUNT(column_id) = COUNT(ts_two)) as no_nulls FROM table_two
GROUP BY column_id
) AS t2
ON t1.column_id = t2.column_id
WHERE t2.column_id IS NULL OR (t2.column_id IS NOT NULL AND t2.no_nulls = TRUE)
SQLFiddle: http://sqlfiddle.com/#!2/14855/8/0
Query everything from table 1
Query each id from table 2, along with whether it has any null ts_two entries for that id.
Joins them together if 1 is missing from 2, or if 1 is in 2 and has no null ts_two entries.
Updated Fiddle: http://sqlfiddle.com/#!2/0b39d2/15/0
SELECT *
FROM Table_one A
LEFT JOIN Table_Two B
on A.Column_ID = B.ColumN_ID
LEFT JOIN (Select column_ID
From table_two
where ts_one is null or ts_two is null) C
ON A.ColumN_Id = C.Column_ID
WHERE C.Column_ID is null
OR B.Column_ID is Null;
What this does:
Returns all data from table 1 in Set 1
Joins to data from table two which are not in 1,5 (Adds data to set 1)
Joins to data from table two that has been filtered to only include records with nulls (creates a 2nd set)
Excludes records where matches exist in 2nd join to table two. (Filters data so that only data in first set and not in second set is returned.
for your first question " id in table_one.column_id and not in table_two.column_id(1, 5)
"
this query should do
SELECT column_id
FROM table_one AS o
WHERE NOT EXISTS (SELECT 1 FROM table_two WHERE column_id = o.column_id)
for your second question "id in table_one.column_id and in table_two.column_id where ts_two is not null and there is no id with a null value - (only 4)"
this query should also do
SELECT t.* FROM table_two AS t
INNER JOIN table_one AS o ON o.column_id = t.column_id
WHERE t.ts_two IS NOT NULL AND NOT EXISTS (SELECT 1 FROM table_two WHERE ts_two IS NULL AND column_id = o.column_id)
the question is so confusing. but from the comments below this should give you what you need
SELECT DISTINCT column_id
FROM (
SELECT column_id
FROM table_one AS o
WHERE NOT EXISTS (SELECT 1 FROM table_two WHERE column_id = o.column_id)
UNION
SELECT t.column_id FROM table_two AS t
INNER JOIN table_one AS o ON o.column_id = t.column_id
WHERE t.ts_two IS NOT NULL AND NOT EXISTS (SELECT 1 FROM table_two WHERE ts_two IS NULL AND column_id = o.column_id)
) AS t

How to update by reading and looping through all the rows?

The following is an example structure:
table `pligg`
#id #alpha #num
1 a null
2 b null
3 c null
4 a null
5 d null
6 b null
7 a null
8 e null
I'd like to update the databse like this after a single mysqli query:
table `pligg`
#id #alpha #num
1 a 1
2 b 1
3 c 1
4 a 2
5 d 1
6 b 2
7 a 3
8 e 1
What I'm trying to do is to update the column num with the number of duplicate.
I tried this query, but in vain
UPDATE pligg SET 'num' = COUNT(DISTINCT alpha) WHERE 'id'<id
This should do the trick:
UPDATE pligg a
INNER JOIN
(
SELECT a.id, a.alpha, COUNT(1) AS dup_cnt
FROM pligg a
INNER JOIN pligg b ON a.id >= b.id AND a.alpha = b.alpha
GROUP BY a.id, a.alpha
) b ON a.id = b.id
SET a.num = b.dup_cnt
SQLFiddle Demo