Detect duplicates within two MySQL columns (unique values scattered across columns) - mysql

I have a MySQL table that contains identifiers spread across two columns:
left right
1 2
3 6
4 5
Using SQL how to find out whether the table contains any duplicate identifier?
For instance, the example above is OK but the examples below are not OK:
left right
1 2 <--+
3 6 | Not OK
4 1 <--+
left right
1 2
3 3 <-- Not OK
4 5
left right
1 2
3 6 <--+ Not OK
4 6 <--+
I am legally not allowed to modify anything in this database, so my question is not about enforcing this in the schema or via triggers or stored procedures I can not modify the database's schema, but rather how to check using just SELECT-type operation(s).
If it was a single column I would write SELECT left FROM MyTable GROUP BY left HAVING COUNT(*) > 1; but for two columns I am not sure how to proceed...

Use UNION ALL to get all values, left and right, in one column:
select value
from
(
select left as value from mytable
union all
select right as value from mytable
) all_values
group by value
having count(*) > 1;

if any any values of left exist in right then it is duplicate so you use sub-query and aggregate function
select case when count(*)>0 then 'deplicate' else 'not' end as result from your_table
where left in (select distinct right from your_table t2)
http://sqlfiddle.com/#!9/ce69b8/2

Related

Select From table name obtained dynamically from the query

I have 3 Tables
campaign1 (TABLE)
id campaign_details
1 'some detail'
campaign2 (TABLE)
id campaign_details
1 'some other detail'
campaign_list (TABLE)
id campaign_table_name
1 'campaign1'
2 'campaign2'
Campaign list table contains the table name of the two tables described above. I want to Select from the Campaign List table and get the record count using the table name i get from this select
For eg.
using select i get campaign1(Table name). Then i run select query on campaign1 to count number of records.
What i'm doing right now is .
-Select from campign_list
-loop through all campaign_table_names and run select query individually
Is there a way to do this using a single query
something like this
select campaign_name,(SELECT COUNT(*) FROM c.campaign_name) as campcount from campaign_list c
SQLFiddle : http://sqlfiddle.com/#!9/b766d/2
It's not possible inside a single query to build it dynamically but it's possible to cheat. Especially if there are only two linked tables.
I've listed two options
left outer join both tables
select campaign_name,
coalesce(c1.campaign_details, c2.campaign_details)
from campaign_list c
left join campaign1 c1 using (id)
left join campaign2 c2 using (id);
union all two different selects
select campaign_name,
campaign_details
from campaign_list c
join campaign1 c1 using (id)
union all
select campaign_name,
campaign_details
from campaign_list c
join campaign2 c2 using (id);
sqlfiddle
Combine your campaign tables to 1 table and add an column named 'type' (int).
campaign_items tables:
item_id item_details item_type
1 'some detail' 1
2 'some detail' 1
3 'some other detail' 2
4 'some other detail' 2
campaign_lists table
campaign_id campaign_name
1 'campaign1'
2 'campaign2'
Then you can use the following select statement:
SELECT campaign_name, (SELECT COUNT(*) FROM campaign_items WHERE item_type = campaign_id) as campaign_count
FROM campaign_lists
Oops, writing took me so long that you got this answered by Colin Raaijmakers already. Well, I'll post my answer anyway in spite of being more or less the same answer. Maybe my elaboration helps you see the problem.
Your problem stems from a bad database design. A database is made to order data and its relations. A CD database holds albums, songs, artists, etc. A business database may hold items, warehouses, sales and so on. Your database holds table names. [... time for thinking :-) ]
(When writing a DBMS you would want to store table names, column names, constraints etc., but I guess I am right supposing that you are not writing a new DBMS.)
So create tables that deal with your actual data. E.g.:
campain_type (id_campain_type, description, ...)
campain (id_campain, id_campain_type, campain_date, ...)
campain_type
id_campain_type description
1 Type A
2 Type B
3 Type C
campain
id_campain id_campain_type date
33 1 2015-06-03
85 2 2015-10-23
97 2 2015-12-01
query
select
ct.description,
(select count(*) from campain c where c.id_campain_type = ct.id_campain_type) as cnt
from campain_type ct;
result
description cnt
Type A 1
Type B 2
Type C 0

common values b/w fields

This table lists user and item id's
user_id item_id
1 1
1 2
1 3
2 1
2 3
3 1
3 4
3 3
How can I run a query on this table to list all the items that are common between given users.
My guess is, this will need a self join, but I'm not sure.
i am trying this quering but it's returning an error
SELECT *
FROM recs 1
JOIN recs 2 ON 2.user_id='2' AND 2.item_id=1.item_id
WHERE 1.user_id='1'
Try using alias names that start in a letter:
SELECT *
FROM recs r1
JOIN recs r2 ON r2.user_id='2' AND r2.item_id=r1.item_id
WHERE r1.user_id='1'
This returns
user_id item_id
------- -------
1 1
1 3
for your data. Demo on sqlfiddle.
Note: I kept single quotes in the query, because I assume that both IDs in your table are of character type. If that is not the case, remove single quotes around user ID values '1' and '2'.
I want it for n number of users ... a I want the query to return all item_id's that are common among the users
SELECT DISTINCT(r1.item_id)
FROM recs r1
WHERE EXISTS (
SELECT *
FROM recs r2
WHERE r2.item_id=r1.item_id
AND r1.user_id <> r2.user_id
)
Demo #2.

Add a column to result, which is another SELECT with dependency

This one is a little bit tricky, at least to me to explain, so please, don't get mad if you don't get the point - it's likely caused by my poor explanation.
I want to get one more column from my main SELECT, which will represent number of rows from another table, suiting id of main record.
So, imagine main table, which I am selecting from. I'll call it simply main.
What I want to select from main, basically is:
SELECT * FROM main ORDER BY c1 ASC LIMIT 5
Plus I need one extra column for each row returned, which says number of rows from side table, matching the id:
SELECT COUNT(*) FROM side WHERE m_id = main_id
Maybe an example will tell you a little bit more
id data1 data2 id m_id ...
main ----|-------|------- side -----|------|-----
1 aa ab 1 1
2 xx yy 2 2
3 az bz 3 1
4 1
5 3
6 2
7 1
8 1
9 2
expected result:
id data1 data2 num
----|-------|-------|------
1 aa ab 5
2 xx yy 3
3 az bz 1
A simple way to add the count is with a correlated subquery:
SELECT m.*,
(select count(*) from side s where s.m_id = m.main_id) as side_cnt
FROM main m
ORDER BY c1 ASC
LIMIT 5;
You can also do this by changing the from clause. However, this method only affects the select part of the query.
You should be able to do it as a subquery:
SELECT m.*, ( SELECT COUNT(*) FROM side WHERE m_id = m.main_id ) as num FROM main m ORDER BY c1 ASC LIMIT 5
This basically runs a special query for each result that counts the number of matching results and displays it in the "num" column.

sql query has few rows which are duplicate

I want the value for users with the right ref and also users with extra value 1.
I have the following query but its not giving unique rows ,its giving duplicate rows.How do I resolve that ? I really appreciate any help.
basically its repeating values of ref.id if tab2.user=1 which repeats 4,6 row again in the final query I dont want both but only one as ref.id=0 does not exist but I want extra=1.
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND tab1.to_users = 1
OR users.extra=1;
Tab1
sno users ref extra
1 1 4 1
2 2 5 0
3 3 0 1
4 1 0 1
5 2 5 0
6 3 0 1
Tab2
ref ad user
4 A 1
5 B 2
6 C 1
After your last comment:
SELECT sno, users, tab1.ref, extra, max(ad) as ad
FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND tab1.users = 1
OR tab1.extra=1
group by sno, users, ref, extra;
This will max the ad column (alternatively you can use min - all depends on your requirements)
example: http://sqlfiddle.com/#!2/1837e/25
You will probably need to use join
SELECT * FROM
tab1 LEFT JOIN tab2 ON tab1.ref=tab2.ref
WHERE tab1.users = 1 OR tab1.extra=1;
GROUP BY tab1.users
edit: added group by
GROUP BY users, give below syntax a try
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref AND (tab1.users = 1 OR tab1.extra=1)
GROUP BY users;
Its more common to also join tables than they way you write your syntax,
SELECT * FROM
tab1 JOIN tab2 ON tab1.ref=tab2.ref AND (tab1.users = 1 OR tab1.extra=1)
GROUP BY users;
You should use parenthesis to change the priority of And and OR :
SELECT * FROM
tab1,tab2
WHERE tab1.ref=tab2.ref
AND (tab1.to_users = 1
OR users.extra=1);
otherwise it will be run like this :
SELECT * FROM
tab1,tab2
WHERE (tab1.ref=tab2.ref
AND tab1.to_users = 1 )
OR users.extra=1;
UPDFATE:
I thought you were looking for rows with same reference where to_users is one or extra is one. Then as Krzysztof RosiƄski says LEFT JOIN should do the trick but there's no need to use GROUP BY and perhaps you should use DISTINCT something like this :
SELECT DISTINCT * FROM
tab1 LEFT JOIN tab2 ON tab1.ref=tab2.ref
WHERE tab1.users = 1 OR tab1.extra=1;

Insert from a list

Is it possible to insert from a list of values from within in mysql?
INSERT INTO changes(uid,typ)
SELECT owner,(SELECT * FROM(20,30,40)) lst
FROM info
To put it another way, can you make a list of values act like the result a sub query?
Actually, what you're trying to do is sintactically and semantically incorrect :) You're trying to return 3 rows from a select and put them into the outer select which just accepts one single value (1 column x 1 row).
Besides there is no way for MySQL to know to which user correponds each number, right? Then, if you had a way to link a user in the inner select to the outer select then you would have two tables and you would join them.
Now if you are actually looking to join each owner to each of the numbers you're looking for a cartesian product. And you can do it like this:
select owner from info, (select 20 union select 30 union select 40) t2
This way, we're creating a dummy table with 3 records and each of those records we're linking them to the owner, this would result in:
owner1 | 20
owner1 | 30
owner1 | 40
owner2 | 20
owner2 | 30
owner2 | 40
owner3 | 20
And so on. Is it clear?