Duplicate column name error during union - mysql

I'm using this query to count rows resulting from 2 tables using union and an alias at the end of the query but it's not working:
SELECT COUNT(*) FROM (
(SELECT * FROM bills INNER JOIN cats INNER JOIN suppliers
INNER JOIN new_cards
WHERE new_cards.`Card_Code` LIKE '%8%'
AND bills.`Sup_ID` = suppliers.`Sup_ID`
AND new_cards.`Sup_ID` = suppliers.`Sup_ID`
AND cats.`Cat_ID` = bills.`Cat_ID`
AND bills.`Cat_ID` = cats.`Cat_ID`
AND new_cards.`Bill_ID` = bills.`Bill_ID`)
UNION
(SELECT * FROM bills INNER JOIN cats INNER JOIN suppliers
INNER JOIN sold_cards WHERE
sold_cards.`Card_Code` LIKE '%8%'
AND bills.`Sup_ID` = suppliers.`Sup_ID`
AND sold_cards.`Sup_ID` = suppliers.`Sup_ID`
AND cats.`Cat_ID` = bills.`Cat_ID`
AND bills.`Cat_ID` = cats.`Cat_ID`
AND sold_cards.`Bill_ID` = bills.`Bill_ID`)
) w
the error is
Error Code: 1060
Duplicate column name 'Cat_ID'

Seems you have a column called Cat_ID in both cats and bills tables. When you do a select * on a join on the tables you will get duplicate column names.
Some possible solutions:
Rename the Cat_ID column in one of the tables
Explicitly name the columns in your select, i.e. instead of "*" use "bills.Cat_ID AS new_name, ...."

These are not variables, it's ok to join or union tables with duplicated column names. See below.
Is the error coming from the union or the join? Try running just the first sub-select, then just the second sub-select.
As a possible workaround, it looks like you could factor out the union of the two cards tables, and SELECT FROM bills JOIN cats JOIN suppliers JOIN (SELECT * from new_cards UNION SELECT * from sold_cards) cards WHERE ...
UNION merges duplicate rows (UNION ALL returns all rows from both sides). If you know you won't have duplicates, you could avoid the union altogether and select just the sum of two counts directly, ie select (select count(*) from ...joins...) + (select count(*) from ...joins...).
None of this answers why it would return an error.
I ran a quick test, which worked:
create table a (id int, a int, b int);
create table b (id int, a int, b int);
insert into a values (1,1,1), (2,2,2);
insert into b values (3,3,3);
select count(*) from ( (select * from a) union (select * from b) ) t;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
select * from ( (select * from a) union (select * from b) ) t;
+------+------+------+
| id | a | b |
+------+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+------+------+------+
3 rows in set (0.00 sec)
select count(*) from a inner join b where a.a = b.a and b.a = a.a;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)

Oh, I see it -- the error is coming from the nested select temp tables.
When running the query, mysql must create a temporary table for each of the two inner selects. It's those temp tables that error out, because you can't create a table with two identically named columns.
If you equated the two Cat_ID's in the join condition instead of in the WHERE, mysql should recognize that they're identical and it should work; something like:
SELECT COUNT(*) FROM (
SELECT * FROM bills
JOIN cats USING (Cat_ID)
JOIN suppliers USING (Sup_ID)
JOIN sold_cards USING (Bill_ID, Sup_ID)
UNION
SELECT * ...
)
Or like Svea said, select a specific column like cats.Cat_ID to count. (And selecting just one column will run faster than selecting all)
select * from (select * from a join b) t;
ERROR 1060 (42S21): Duplicate column name 'id'
select * from (select * from a join b using (id, a, b)) t;
Empty set (0.00 sec)

Related

Select all rows that have same ID

I have this table:
ID | Part
1 | A
1 | B
1 | C
2 | B
2 | C
3 | A
3 | D
3 | E
4 | B
4 | D
and want a query that will grab all ID's that have an A, and return a list of all other parts with that ID.
e.g: Want Parts related to B:
Part | Count
A | 1
C | 2
D | 1
What I have currently:
SELECT * FROM tble WHERE ID IN (SELECT DISTINCT ID FROM tble t WHERE Part = ?)
GROUP BY Part ORDER BY COUNT(Part) DESC
This works, but is quite slow and I'm looking to improve it, but having difficulty
Your query is not unreasonable, although the distinct is unnecessary and I would use exists rather than in. And, the outer select needs to be fixed for the aggregation
SELECT t.part, COUNT(*)
FROM tble t
WHERE EXISTS (SELECT 1 FROM tble t2 WHERE t2.ID = t.ID AND t2.Part = ?)
GROUP BY t.Part
ORDER BY COUNT(*) DESC;
Then, to optimize this query, you want an index:
create index idx_tble_id_part on tble(id, part);
Simplify this.. Once you have the logic down, then add back in the SELECT * FROM..
SELECT Part, COUNT(Part) As Count_of_Part
GROUP BY Part ORDER BY COUNT(Part) DESC
Do a join from the table back to itself on ID, and then count the distinct values that pop up:
SELECT b.part, COUNT(DISTINCT b.id)
FROM
table as a
INNER JOIN table as b ON
a.id = b.id AND
a.part <> b.part
WHERE
a.part = 'B'
GROUP BY b.part
This can be simply done by joining back to the table:
SELECT t1.part
,count(*)
FROM tble t1
INNER JOIN tble t ON t.id = t1.id
AND t.part = 'B'
AND t1.part <> t.part
GROUP BY t1.part
SQL Fiddle Demo
You should be able to do this by grouping the data.
Try something like this:
SELECT part, COUNT(id) AS TotalCountId
FROM TABLE_NAME
GROUP BY ID

mysql union of 2 tables

I have 2 tables:
table A (id, user_id, flag)
table B (id, user_id, flag)
Here If I take Count of table A it comes as 10 and that of B 5
So Total = 10 + 5 = 15.
SELECT * FROM table A
LEFT JOIN table B ON table B.user_id = table A.user_id
UNION ALL
SELECT * FROM table A
RIGHT JOIN table B ON table B.user_id = table A.user_id
So It should Come 15 instead it showing 50.
use
SELECT * FROM TABLE1 UNION
SELECT * FROM TABLE2
UNION removes duplicate records in other hand UNION ALL does not.Check HERE
You need to make sure the data in your tables are correct.
Table A Should have 15 rows
SELECT COUNT(*) as 'rowCountTableA' FROM table_a;
Table B Should have 5 rows
SELECT COUNT(*) as 'rowCountTableB' FROM table_b;
If your tables are correct and have exactly matching column names you can join them together by specifying asterisks to get all column values.
If however the columns in your table have a few different column names that are in table_a that are not in table_b you must call out the column names instead of using asterisk to get all values.
EXAMPLE:
SELECT (id,user_id,flag) FROM table_a
UNION ALL
SELECT (id,user_id,flag) FROM table_b

Select Matched Pairs from Two Tables

I need to select matched pairs from two tables containing similarly structured data. "Matched Pair" here means two rows that reference each other in the 'match' column.
A single-table matched pair example:
TABLE
----
id | matchid
1 | 2
2 | 1
ID 1 and 2 are a matched pair because each has a match entry for the other.
Now the real question: what is the best (fastest) way to select the matched pairs that appear in both tables:
Table ONE (id, matchid)
Table TWO (id, matchid)
Example data:
ONE TWO
---- ----
id | matchid id | matchid
1 | 2 2 | 3
2 | 3 3 | 2
3 | 2
4 | 5
5 | 4
The desired result is a single row with IDs 2 and 3.
RESULT
----
id | id
2 | 3
This is because 2 & 3 are a matched pair in table ONE and in table TWO. 4 & 5 are a matched pair in table ONE but not TWO, so we don't select them. 1 and 2 are not a match pair at all since 2 does not have a matching entry for 1.
I can get the matched pairs from one table with this:
SELECT a.id, b.id
FROM ONE a JOIN ONE b
ON a.id = b.matchid AND a.matchid = b.id
WHERE a.id < b.id
How should I build a query that selects only the matching pairs that appear in both tables?
Should I:
Select the query above for each table and WHERE EXISTS them together?
Select the query above for each table and JOIN them together?
Select the query above then JOIN table TWO twice, once for 'id' and once for 'matchid'?
Select the query above for each table and loop through to compare them back in php?
Somehow filter table TWO down so we only have to look at the IDs in matched pairs in table ONE?
Do something totally different?
(Since this is a question of efficiency, it is worth noting that the matches will be quite sparse, maybe 1/1000 or less, and each table will have 100,000+ rows.)
I think I get your point. You want to filter the records in which the pairs exists on both tables.
SELECT LEAST(a.ID, a.MatchID) ID, GREATEST(a.ID, a.MatchID) MatchID
FROM One a
INNER JOIN Two b
ON a.ID = b.ID AND
a.matchID = b.matchID
GROUP BY LEAST(a.ID, a.MatchID), GREATEST(a.ID, a.MatchID)
HAVING COUNT(*) > 1
SQLFiddle Demo
Try this Query:
select
O.id,
O.matchid
from
ONE O
where
(CAST(O.id as CHAR(50))+'~'+CAST(O.matchid as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
Edited Query:
select distinct
Least(O.id,O.matchid) ID,
Greatest(O.id,O.matchid) MatchID
from
ONE O
where
(CAST(O.id as CHAR(50))+'~'+CAST(O.matchid as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
and (CAST(O.matchid as CHAR(50))+'~'+CAST(O.id as CHAR(50)))
in (select CAST(T.id as CHAR(50))+'~'+CAST(T.matchid as CHAR(50)) from TWO T)
SQL Fiddle
Naive version, which checks all the four rows that need to exist:
-- EXPLAIN ANALYZE
WITH both_one AS (
SELECT o.id, o.matchid
FROM one o
WHERE o.id < o.matchid
AND EXISTS ( SELECT * FROM one x WHERE x.id = o.matchid AND x.matchid = o.id)
)
, both_two AS (
SELECT t.id, t.matchid
FROM two t
WHERE t.id < t.matchid
AND EXISTS ( SELECT * FROM two x WHERE x.id = t.matchid AND x.matchid = t.id)
)
SELECT *
FROM both_one oo
WHERE EXISTS (
SELECT *
FROM both_two tt
WHERE tt.id = oo.id AND tt.matchid = oo.matchid
);
This one is simpler :
-- EXPLAIN ANALYZE
WITH pair AS (
SELECT o.id, o.matchid
FROM one o
WHERE EXISTS ( SELECT * FROM two x WHERE x.id = o.id AND x.matchid = o.matchid)
)
SELECT *
FROM pair pp
WHERE EXISTS (
SELECT *
FROM pair xx
WHERE xx.id = pp.matchid AND xx.matchid = pp.id
)
AND pp.id < pp.matchid
;

Mysql delete in one table by id's from another table

I have two tables:
A
id | name
and
B
id | name
On B table i create query to select all data, where id's are in (... some values), but how can i in one query select this B - id's and delete from A where A.id = B.id ?
I'm new to sql.... Could not find how to combine all in one query...
*i must select from b on some like query, for example my b query: select * from B where somefieldinteger in (1,4,9,21,25) and that b.id must compare with a*
upd
this throw error
delete `LINK_LA_TYP` FROM `LINK_LA_TYP` JOIN `LINK_ART` ON `LINK_LA_TYP`.LAT_LA_ID=`LINK_ART`.LA_ID JOIN `ARTICLES` ON `LINK_ART`.LA_ART_ID=`ARTICLES`.ART_ID WHERE (`ARTICLES`.ART_SUP_ID in (10008,10439,11005,10097,10669,11100,80,10912,10683,10675,10194,11196,1166,10730,10248,10870,11200,11059,247,10121,10911,489,10724,496,10093,10205,1318,10953,11199,11047,128,114,194,10865,11058,10345,1286,10667,10064,11077,10622,11205,10917,10344,495,10709,10954,10744,304,10957,10447,10764,10129,10862,10918,10731,11115,10095,10859,10580,1345,10177,10323,144,11182,10132,256,10941,58,10006,10017,10780,10765,10665,11110,10714,10224,750,10267,10179,10725,10774,11063,10868,10103,10676,10057,10649,255,10322,11022,309,10754,11121,10801,10018,11004,10245,146,11056,381,10781,10699,11120,11126,830,10240,11162,10436,10584,10342,10861,11190,10721,11171,10564,10545,94,10087,73,10755,10869,10547,10706,10346,444,426,10059,153,122,10674,64,113,11101,10231,10337,806,11117,10385,251,11188,491,11192,100,10792,10069,10864,11099,10246,10178,10758,10568,10230,10124,10384,10782,10726,384,10670,305,10763,10768,10585,10394,10552,498,10677,1348,168,10814,10582,10382,11093,11173,10381,427,441)) limit 50
Use delete together with join like this:
mysql> create table a (id int);
mysql> insert into a values (1), (2), (3), (4);
mysql> create table b (id int);
mysql> insert into b values (2), (3);
mysql> delete a from a join b on a.id=b.id where b.id > 2;
mysql> select * from a;
+------+
| id |
+------+
| 1 |
| 2 |
| 4 |
+------+
This scales to arbitrary number of tables, e.g.:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB;
This will delete from a all records that are referred from those records of b which are in turn referred from c. You may also add WHERE clause like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
WHERE a.status='done' AND
b.status='open' AND
c.status='open';
If you want to limit number of rows to be deleted, do like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
LIMIT 500000;
If you want to delete first 500000 rows, you need to refine which rows are first, so you need to establish some ordering among rows. In other words you need to sort rows by some criteria and then limit like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
ORDER BY a.something
LIMIT 500000;
delete from A where exists (select 1 from B where A.id=B.id and B.criteria=true)
If you leave out ... and B.criteria=true it would delete all rows in A that appear in B; otherwise you delete whatever matches your criteria.

mysql left join returns unexpected amount of rows

I have 2 tables where
tableA has 41 rows
and
tableB has 3 rows
I am trying to get the total rows of these 2 tables via a query using left join but i get way more rows(123) than expected(44)
query:
SELECT COUNT(*)
FROM tableA as u
LEFT JOIN tableB as d
ON u.uid=d.uid
WHERE
u.uid=912391178669
AND
u.deleted = 0
AND
d.deleted=0
tables schema:
tableA
id | uid | deleted
tableB
id | uid | deleted
I have run the following query It is working correctly.. U can check it out.
SELECT
( SELECT count(*) from table1 where.... )
+ ( SELECT count(*) from table2 where.... )
as total from dual
I'm guessing that you have three rows in tableA with the uid given in the query. That will mean that each row in tableA will join once with each row in tableB, which means you will back 41 x 3 rows or 123.
From the number of rows you are expecting back, I wonder if you need a Union instead of a join.
Select * from tableA where uid = 912391178669 and deleted = 0
union all
Select * from tableB where uid = 912391178669 and deleted = 0
A union will combine the results of two queries. A join will combine the columns of table tables in a single query.
41*3=123
each row of TableA has uid=912391178669 and tableB each row also have uid that's why you are getting 123 row total. use some filter criteria to get desired result (like some AND condition)
if you can show us your table column then it may be possible to help you .
Left join does not combine the rows of two table .
TableA left join TableB will give you all the row of table A meeting the joining condition.
SELECT COUNT(*)
FROM tableA as u
LEFT JOIN tableB as d
ON u.uid=d.uid
AND
u.deleted = d.deleted
WHERE
u.uid=912391178669
AND u.deleted = 0
SELECT SUM(
(SELECT count(*) from tableA WHERE uid=912391178669)
+ (SELECT count(*) from tableA WHERE uid=912391178669)
) as totalRows