Left join on the same table - mysql

i dont remember how to join a table to itself.. my table is:
| id | proc | value | kind |
| 1 | 1 | foo | a |
| 2 | 1 | bar | b |
| 3 | 2 | some | a |
And i need to retrieve the value col where proc is $proc and kind is both 'a' and 'b'.. well, i need to do have that (looking for proc = 1):
| v_a | v_b |
| foo | bar |
So i wrote this query:
SELECT
a.value AS v_a,
b.value AS v_b
FROM
(SELECT value FROM table WHERE proc = '1' AND kind = 'a') AS a,
(SELECT value FROM table WHERE proc = '1' AND kind = 'b') AS b
And works but only if in the table i have both rows for kind=a and kind=b.
But i need that if miss a row, i'll have a null value: if i look for proc=2 i must get:
| v_a | v_b |
| foo | NULL|
Instead, with my query i dont get anythong if the b or a row is missing.
Im working with mysql...How to do that?
Edit:
I could use the UNION clause, but this wont allow me to have a NULL value when one row is missing (kind=a or kind=b)

you have to do a full join in case proc exists for 'a' but not for 'b' or vice versa:
SELECT
a.value v_a,
b.value v_b
FROM (SELECT proc, value FROM tab WHERE kind = 'a') a LEFT JOIN
(SELECT proc, value FROM tab WHERE kind = 'b') b
ON a.proc = b.proc
WHERE a.proc = '1'
UNION
SELECT
a.value v_a,
b.value v_b
FROM (SELECT proc, value FROM tab WHERE kind = 'b') b LEFT JOIN
(SELECT proc, value FROM tab WHERE kind = 'a') a
ON a.proc = b.proc
WHERE b.proc = '1'
EDIT: 1st a gave MS SQL Server query (FULL JOIN) but apparently it's not supported by MYSQL, so I changed it to a UNION of 2 LEFT JOIN

I missed your need to retrieve NULLs. This is complicated, but it seems to work:
SELECT
a.value AS a_val,
(SELECT value FROM t b2 WHERE b2.proc = a.proc AND b2.id != a.id) AS b_val
FROM `t` a
WHERE a.kind = 'a'
UNION DISTINCT
SELECT
(SELECT value FROM t a2 WHERE a2.proc = b.proc AND a2.id != b.id) AS a_val,
b.value AS b_val
FROM `t` b
WHERE b.kind = 'b'

select * from t1 full outer join t2 on some_id = some_other_id?

SELECT
a.value AS v_a,
b.value AS v_b
FROM
(SELECT proc, value FROM table WHERE proc = '1' AND kind = 'a') AS a
LEFT OUTER JOIN
(SELECT proc, value FROM table WHERE proc = '1' AND kind = 'b') AS b
ON a.proc=b.proc

Related

Mysql return result missing from the IN-Clause

I want to return values which are not present in the IN Clause within the same table.
select * from tableA where columnA in ('aa', 'bb', 'cc')
I will get back only result which exist in that table like
id | columnA | columnB
----------------------
1 | aa | text
2 | bb | text2
What I am require is something like
id | columnA | columnB
----------------------
null| cc |
essentially record which dont exist. My question is similar to - Find missing data passed to SQL in-clause, but it is for Oracle. I am looking for Mysql.
I tried something like this but it didnt work
SELECT
t1.id,
t1.columnA,
t1.columnB
FROM
tableA t1
LEFT JOIN tableA t2 ON t1.columnA = t2.columnA
WHERE
t2.columnA IS NULL
AND t1.columnA in('aa', 'bb', 'cc')
You can construct the values using a derived table and then use left join on that:
select x.a
from (select 'aa' as columnA union all
select 'bb' as columnA union all
select 'cc' as columnA
) x left join
tableA a
using (columnA)
where a.columnA is null;

need to merge rows into two colums mysql

please advice how to make SQL query in order to get from this table
ID|Number|Type|
----------------
1 |AA1 |IN |
2 |AA2 |OUT |
3 |AA3 |IN |
4 |AA4 |OUT |
into this result
ID| IN | OUT |
-------------------
1 | AA1 | AA2 |
2 | AA3 | AA4 |
Thanks
This Will work using Implicit join.
It will use mysql session variables. for reference, you can read http://www.mysqltutorial.org/mysql-variables/ for session variables.
SET #row_number = 0;
SET #row_number2 = 0;
SELECT
out_table.OUTs AS outs, in_table.Ins as INs FROM
(SELECT
(#row_number2:=#row_number2 + 1) AS num2, Number as OUTs FROM your_table WHERE your_table.Type = 'OUT') as out_table ,
(SELECT
(#row_number:=#row_number + 1) AS num1, Number as Ins FROM your_table WHERE your_table.Type = 'IN') as in_table
WHERE num2 = num1
You can emulate row_number like functionality, using session variables. We get all INs and OUTs separately in two derived tables and do a LEFT JOIN on them, to get the desired output.
This will work even for the cases where IN and OUT are not consecutive. It will also handle the cases where there is an IN without OUT.
It would not work for the case when there is an OUT without IN.
Try the following query:
SET #row_no_1 = 0;
SET #row_no_2 = 0;
SELECT
t1.row_no AS ID, t1.Number AS `IN`, t2.Number AS `OUT`
FROM
(SELECT
#row_no_1:=#row_no_1 + 1 AS row_no, Number
FROM
`your_table`
WHERE
Type = 'IN'
ORDER BY id ASC) AS t1
LEFT JOIN
(SELECT
#row_no_2:=#row_no_2 + 1 AS row_no, Number
FROM
`your_table`
WHERE
Type = 'OUT'
ORDER BY id ASC) AS t2 ON t2.row_no = t1.row_no
answering myself...
SELECT a.ID
MAX(CASE WHEN a.type = "IN" THEN a.Number ELSE "" END) AS IN_Type,
MAX(CASE WHEN b.type = "IN" THEN b.Number ELSE "" END) AS Out_Type
FROM table1 a Left join table1 b on a.ID = b.ID
Group by a.ID

delete rows in mysql

If I have a table:
id1 id2 count
A A 1
A B 2
A C 1
B A 3
B B 1
B C 2
C A 3
C B 2
C C 1
What I want after deleting:
id1 id2 count
A A 1
A B 2
A C 1
B B 1
B C 2
C C 1
which means if I have A(id1) --> B(id2) then delete B(id1) --> A(id2). same as B(id1) --> C(id2) then delete the row C(id1) --> B(id2)
Thank you for ur help!
In this case we analyze Target.id1 > Target.id2 mean case like (B, A, ??) where B > A
this also ignore cases like (A, A, ??)
Then use self left join to try find another row with (A, B, ??)
If we found a match then Source.id1 IS NOT NULL and we delete
SQL Fiddle Demo
DELETE Target
FROM Table1 Target
LEFT JOIN Table1 Source
ON Target.`id1` = Source.`id2`
AND Target.`id2` = Source.`id1`
AND Target.`id1` > Target.`id2`
WHERE Source.`id1` IS NOT NULL;
OUTPUT
| id1 | id2 | count |
|-----|-----|-------|
| A | A | 1 |
| A | B | 2 |
| A | C | 1 |
| B | B | 1 |
| B | C | 2 |
| C | C | 1 |
Should be something like:
DELETE FROM 'myTable'
WHERE STRCMP(id1, id2) > 0;
STRCMP function can compare the strings and return an int. From there it should be easy - something very similar to the above. If you have further trouble let me know.
It looks like what you are saying is...
If there is a (id1,id2) tuple in the table with values e.g. (a,b), and there is another tuple (b,a) that consists of the the same values, but swapped in the columns, you want to remove one of those tuples. It looks like the one you want to remove is the one that has the "greater" value in the first column.
First, identify the "duplicate" tuples.
For now, we'll ignore the tuples where the values of id1 and id2 are the same, e.g. (a,a).
SELECT s.id1
, s.id2
FROM mytable s
WHERE s.id1 > s.id2
AND EXISTS ( SELECT 1
FROM mytable r
WHERE r.id1 = s.id2
AND r.id2 = s.id1
)
ORDER BY s.id1, s.id2
If that returns the set of rows you want to remove, we can convert that into a DELETE. To do that, we need to change that query into an inline view,
We can re-write that to be like this, verify we get equivalent results.
SELECT o.id1, o.id2
FROM ( SELECT q.id1, q.id2
FROM ( SELECT s.id1, s.id2
FROM mytable s
WHERE s.id1 > s.id2
AND EXISTS ( SELECT 1
FROM mytable r
WHERE r.id1 = s.id2
AND r.id2 = s.id1
)
) q
GROUP BY q.id1, q.id2
) p
JOIN mytable o
ON o.id1 = p.id1
AND o.id2 = p.id2
ORDER BY o.id1, o.id2
Then we can convert that to a DELETE statement, replacing SELECT o.id1, o.id2 WITH DELETE o.* and removing the ORDER BY...
DELETE o.*
FROM ( SELECT q.id1, q.id2
FROM ( SELECT s.id1, s.id2
FROM mytable s
WHERE s.id1 > s.id2
AND EXISTS ( SELECT 1
FROM mytable r
WHERE r.id1 = s.id2
AND r.id2 = s.id1
)
) q
GROUP BY q.id1, q.id2
) p
JOIN mytable o
ON o.id1 = p.id1
AND o.id2 = p.id2

mysql query select from one table such that its column's values are not present in the same column's values in another table

I have two mysql tables: A, and B.
A has columns id, alpha, blabla, moreblabla, with primary key id.
B has columns id, alpha, beta, somemoreblabla, with primary key (id, alpha)
I need to select all those A.id's, for which its A.alpha is not present in any of the B.alpha's respective to every B.id = A.id
How do I do it?
Your question is not entirely clear. Do you want all A.alpha's that are not in any B.alpha? In that case a simple query like this is enough:
Select A.id from A where A.alpha NOT IN (Select B.alpha from B);
If you want to select all ID's from A that have a counterpart (an equal ID) in B but where the alpha between A and B are different it is a bit more work:
SELECT A.id FROM A
INNER JOIN B on A.id = B.id
WHERE A.alpha != B.alpha
Consider the following structure:
CREATE TABLE `A` (
`id` int(11) NOT NULL,
`alpha` varchar(255) NOT NULL
);
CREATE TABLE `B` (
`id` int(11) NOT NULL,
`alpha` varchar(255) NOT NULL
);
With inserts:
insert into A set id = 1, alpha = 'a';
insert into A set id = 2, alpha = 'b';
insert into B set id = 1, alpha = 'a';
insert into B set id = 2, alpha = 'a';
If you run the query with the join your result will be:
+----+
| id |
+----+
| 2 |
+----+
This is since ID 2 in A has a different alpha than ID 2 in B.
EDIT:
It just occurred to me that you might even mean that every A.id can occur in B multiple times. If that is what can happen you need a different approach again. Lets assume the same insert as before with an addition:
insert into A set id = 1, alpha = 'a';
insert into A set id = 2, alpha = 'b';
insert into B set id = 1, alpha = 'a';
insert into B set id = 2, alpha = 'a';
insert into B set id = 2, alpha = 'b'; <- important since there is now a 2nd 2 in B that should ensure that the record with ID 2 from A should not be returned.
insert into A set id = 3, alpha = 'c';
insert into B set id = 3, alpha = 'x'; <-- only ID 3 should now be returned due to the situation above
Our tables now look like so:
A
+----+-------+
| id | alpha |
+----+-------+
| 1 | a |
| 2 | b |
| 3 | c |
+----+-------+
B
+----+-------+
| id | alpha |
+----+-------+
| 1 | a |
| 2 | a |
| 2 | b |
| 3 | x |
+----+-------+
If this is your case the following query will do the trick:
select A.id
FROM A where A.alpha NOT IN (
select B.alpha FROM B where B.id = A.id
);
SELECT A.id
FROM
A
LEFT OUTER JOIN B ON A.id = B.id AND B.alpha = A.alpha
where B.alpha IS NULL
Here is SQL Fiddle
This will be the fastest query,better than The marked Answer in terms of query optimization.
EXPLAIN SELECT A.id
FROM
A
LEFT OUTER JOIN B ON A.id = B.id AND B.alpha = A.alpha
where B.alpha IS NULL
Here is the output :
EXPLAIN select A.id
FROM A where A.alpha NOT IN (
select B.alpha FROM B where B.id = A.id
)
Here is the EXPLAIN of Marked answer.
You can see the DIFFERENCE.
SIMPLE VS PRIMARY
SIMPLE VS DEPENDENT SUBQUERY
Hope this helps.
Use MySQL NOT IN
Try this query :-
select id from a where a.id NOT IN (select id from b)
Select A.id from table_A where A.alpha NOT IN (Select B.alpha from table_B);
The Sub-query will return a table with all the records of B.alpha from table_B.
And say it returns 1 to 5 records as result.
And say your table table_A has 1 to 10 records in A.alpha
Now your parent query will check for records in table table_A for field A.alpha which do not belongs to B.alpha (using NOT IN)
Hence the expected result is 6 to 10 as result.

Combining 2 rows in table

I have the following data:
-------table_a-------
| id | data | value |
| 1 | 5 | 1 |
| 2 | 3 | 3 |
My desired output is to merge row 2 with row 1 so that where id = 1, data remains to =5 but the values are added, so 1+3.
-------table_a-------
| id | data | value |
| 1 | 5 | 4 |
This is as far as I got with the queries but the first isn't seeming to work. Also this is not for retrieving the data, this is for manipulating the data in the database.
Current queries (1st not working):
UPDATE table_a SET value = value + (SELECT a.value FROM table_a a WHERE a.id = 2) WHERE id = 1;
DELETE FROM table_a WHERE id = 2;
If this is the logic that you want:
UPDATE table_a
SET value = value + (SELECT a.value FROM table_a a WHERE a.id = 2)
WHERE id = 1;
DELETE FROM table_a WHERE id = 2;
The update is not going to work because you cannot reference the table being updated in the rest of the query. You can use a hack for the update and do:
UPDATE table_a
SET value = value + (SELECT value FROM (SELECT a.value FROM table_a a WHERE a.id = 2) )
WHERE id = 1;
The double select fixes this problem. The more correct method is to use join:
UPDATE table_a a CROSS JOIN
(SELECT a.value FROM table_a a WHERE a.id = 2) as a2
SET a.value = a.value + a2.value
WHERE id = 1;
Here is one way on how you can make an accumulative column by joining the table with itself.
I'm assuming the Id column is an identity column,
Hope this helps.
CREATE TABLE [dbo].[TestTable](
[id] [int] NULL,
[data] [int] NULL,
[value] [int] NULL
) ON [PRIMARY]
INSERT INTO [dbo].[TestTable]
([id]
,[data]
,[value])
VALUES
(1,5,1),
(2,3,3),
(3,4,4)
SELECT a.id , a.data , a.value + b.value as Sum
FROM [TestTable] a
left join [TestTable] b
on a.id + 1 = b.id
This will work, please check.
UPDATE table_a,
(SELECT value as val FROM table_a where id = 2) AS t2
SET table_a.value = table_a.value+t2.val
where table_a.id = 1;
DELETE from table_a where id = 2;