SQL My Sub Query is Loading Forever - mysql

Okay so basically I am trying to run a simple query with a subquery on phpmyadmin using mysql and it won't stop loading after I run it. The query is:
SELECT t.tagValue FROM tags t WHERE t.tagID IN (SELECT ua.tagID FROM user_taggedArtists ua WHERE ua.userID = 2);
I have ran the individual queries on their own without combining them together and they seem to do what I want, but when I mix them into a subquery form phpmyadmin just loads forever, like I am getting an infinite loop or something.
tags table looks like that:
╔═══════╦═════════════╗
║ tagID ║ tagValue ║
╠═══════╬═════════════╣
║ 1 ║ metal ║
║ 2 ║ alternative ║
║ 3 ║ pop ║
╚═══════╩═════════════╝
etc.
user_taggedArtists table looks like this:
╔════════╦══════════╦═══════╦═════╦═══════╦═══════╗
║ userID ║ artistID ║ tagID ║ day ║ month ║ year ║
╠════════╬══════════╬═══════╬═════╬═══════╬═══════╣
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
║ 2 ║ 52 ║ 1 ║ 1 ║ 4 ║ 2009 ║
╚════════╩══════════╩═══════╩═════╩═══════╩═══════╝
ect.
Not sure what I am doing wrong here and any help would be greatly appreciated.
Thank you!

Hard to say 'zatly, but "IN", generally, is slow. Try a JOIN and WHERE. I'm going to pretend we can join on tagID. You should have indexes on the join column(s). If not anything you do will perform poorly.
SELECT t.tagValue
FROM tags t
INNER JOIN user_taggedArtists ua ON
t.tagID = ua.tagID
WHERE ua.userID = 2

Related

SQL: Select ID/Value combinations that do not possess a value in another table

So here's basically the issue (I'm turning this into more of a universal question in case people need something like this in the future).
I have one table ("People") that is basically this
╔══════════╦═══════╗
║ PersonID ║ Letter║
╠══════════╬═══════╣
║ 1 ║ A ║
║ 1 ║ B ║
║ 1 ║ C ║
║ 1 ║ D ║
║ 2 ║ A ║
║ 2 ║ B ║
║ 2 ║ C ║
║ 3 ║ B ║
║ 3 ║ C ║
║ 4 ║ A ║
║ 4 ║ C ║
║ 4 ║ D ║
║ 5 ║ E ║
╚══════════╩═══════╝
And lets say I have another table ("Letters") which can lists all possible "Letters" a person can have.
╔══════════╦══════╗
║ LetterID ║ Text ║
╠══════════╬══════╣
║ 1 ║ A ║
║ 2 ║ B ║
║ 3 ║ C ║
║ 4 ║ D ║
║ 5 ║ E ║
╚══════════╩══════╝
I need to make a new table that will have all persons listed and letters that they DONT have. So for this example, the result would be this
╔══════════╦══════════════╗
║ PersonID ║ LetterNotHad ║
╠══════════╬══════════════╣
║ 1 ║ E ║
║ 2 ║ D ║
║ 2 ║ E ║
║ 3 ║ A ║
║ 3 ║ D ║
║ 3 ║ E ║
║ 4 ║ B ║
║ 4 ║ E ║
║ 5 ║ A ║
║ 5 ║ B ║
║ 5 ║ C ║
║ 5 ║ D ║
╚══════════╩══════════════╝
Any and all help or guidance is greatly appreciated.
Edit: Here's basically what I was trying, something like this
select p.PersonId, l.value
from letters l
left join people p
on l.Text = p.Letter
where p.personid is null
Here is the idea
WITH cte
AS (SELECT *
FROM (SELECT DISTINCT personid
FROM people) B
CROSS JOIN (SELECT DISTINCT Text as letter
FROM letters) A)
SELECT *
FROM cte c
WHERE NOT EXISTS (SELECT 1
FROM first_table f
WHERE c.personid = f.personid
AND c.letter = f.letter)
Note: You need to use letterid in People table instead of Letter and define a foreign key which make the table's consistent
So what you want to do in order to find the missing values is to generate the set that represents all possible values. This is the cartesian product between the two sets (people and letters) and in SQL you use the cross join operator (or unqualified join) to do this.
From this set you want to remove the combinations you already have, and the remainder will be the missing ones.
There are many ways to do this; using a left join it could look like this:
select sub.*
from (
select distinct personid, text
from people
cross join letters
) sub
left join people p on p.letter = sub.text and p.personid = sub.personid
where p.personid is null
Or using the except set operator (for MSSQL (minus in Oracle) - MySQL does not have this):
select personid, text from people cross join letters
except
select personid, letter from people

De-duplicating many-to-many relationships in MySQL lookup table

I've inherited a database that includes a lookup table to find other patents that are related to a given patent.
So it looks like
╔════╦═══════════╦════════════╗
║ id ║ patent_id ║ related_id ║
╠════╬═══════════╬════════════╣
║ 1 ║ 1 ║ 2 ║
║ 2 ║ 1 ║ 3 ║
║ 3 ║ 2 ║ 1 ║
║ 4 ║ 2 ║ 3 ║
║ 5 ║ 3 ║ 2 ║
╚════╩═══════════╩════════════╝
And I want to filter out the reciprocal relationships. 1->2 and 2->1 are the same for my purposes so I only want 1->2.
I don't need to make the edit in the table, I just need a query the returns a list of the unique relationships, and while I'm sure it's simple I've been banging my head against the keyboard for far too long.
Here is a clever query which you can try using. The general strategy is to identify the unwanted duplicate records and then subtract them away from the entire set.
SELECT t.id, t.patent_id, t.related_id
FROM t LEFT JOIN
(
SELECT t1.patent_id AS t1_patent_id, t1.related_id AS t1_related_id
FROM t t1 LEFT JOIN t t2
ON t1.related_id = t2.patent_id
WHERE t1.patent_id = t2.related_id AND t1.patent_id > t1.related_id
) t3
ON t.patent_id = t3.t1_patent_id AND t.related_id = t3.t1_related_id
WHERE t3.t1_patent_id IS NULL
Here is the inner temporary table generated by this query. You can convince yourself that by applying the logic in the WHERE clause you will select the correct records. Non-duplicate records are characterized by t1.patent_id != t2.related_id, and all these records are retained. In the case of duplicates (t1.patent_id = t2.related_id), the record chosen from each pair of duplicates is the one where patent_id < related_id, as you requested in your question.
╔════╦══════════════╦═══════════════╦══════════════╦═══════════════╗
║ id ║ t1.patent_id ║ t1.related_id ║ t2.patent_id ║ t2.related_id ║
╠════╬══════════════╬═══════════════╬══════════════╬═══════════════╣
║ 1 ║ 1 ║ 2 ║ 2 ║ 1 ║ * duplicate
║ 1 ║ 1 ║ 2 ║ 2 ║ 3 ║
║ 2 ║ 1 ║ 3 ║ 3 ║ 2 ║
║ 3 ║ 2 ║ 1 ║ 1 ║ 2 ║ * duplicate
║ 3 ║ 2 ║ 1 ║ 1 ║ 3 ║
║ 4 ║ 2 ║ 3 ║ 3 ║ 2 ║ * duplicate
║ 5 ║ 3 ║ 2 ║ 2 ║ 1 ║
║ 5 ║ 3 ║ 2 ║ 2 ║ 3 ║ * duplicate
╚════╩══════════════╩═══════════════╩══════════════╩═══════════════╝
Click the link below for a running example of this query.
SQLFiddle
Try something like
select distinct * from
(select patient_id, related_id from TABLENAME
union
select related_id, patient_id from TABLENAME
);
Okay you're right the above won't work. Try
select patient_id, related_id from TABLENAME p1
where p1.patiend_id not in
(select patient_id from TABLENAME p2
where p2.related_id = p1.related_id)

MySQL - Merge rows in table based on multiple criteria

I'd like to merge rows based on multiple criteria, essentially removing duplicates where I get to define what "duplicate" means. Here is an example table:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 2 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
║ 5 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
In my example, let's say I want to merge on name and age but ignore grade. The result should be:
╔═════╦═══════╦═════╦═══════╗
║ id* ║ name ║ age ║ grade ║
╠═════╬═══════╬═════╬═══════╣
║ 1 ║ John ║ 11 ║ 5 ║
║ 3 ║ John ║ 11 ║ 6 ║
║ 4 ║ Sam ║ 14 ║ 7 ║
╚═════╩═══════╩═════╩═══════╝
I don't particularly care if the id column is updated to be incremental, but I suppose that would be nice.
Can I do this in MySQL?
My suggestion, based on my above comment.
SELECT distinct name, age, grade
into tempTable
from theTable
This will ignore the IDs and give you only a distinct dump, and into a new table.
Then you can either drop the old and, and rename the new one. Or truncate the old one, and dump this back in.
You could just delete the duplicates in place like this:
delete test
from test
inner join (
select name, age, grade, min(id) as minid, count(*)
from test
group by name, age, grade
having count(*) > 1
) main on test.id = main.minid;
Example: http://sqlfiddle.com/#!9/f1a38/1

(string) LIKE query with join in Mysql

I am trying to join two different columns inside the tables using the strings which is only partially common between the two columns of two different table.
How do i combine these two tables:
Suppose if i have 2 tables, table1, table2
╔════╦══════════════════════════════════╦══════╗
║ T1 ║ String1 ║ snr ║
╠════╬══════════════════════════════════╬══════╣
║ 1 ║ Jeff Atwood is good but naughty ║ 5636 ║
║ 2 ║ Geoff Dalgas is bully and fat ║ 148 ║
║ 3 ║ Jeff Atwood likes skoda and hate ║ ║
║ ║ ferrari ║ 101 ║
║ 4 ║ Geoff Dalgas is smart but not ║ ║
║ ║ intelligent ║ 959 ║
╚════╩══════════════════════════════════╩══════╝
╔════╦══════════════════════════════════╦══════╗
║ T2 ║ String2 ║ bnr ║
╠════╬══════════════════════════════════╬══════╣
║ 5 ║ Jeff Atwood is good ║ 1323 ║
║ 34║ Geoff Dalgas is bully ║12148 ║
║ 73║ Jeff Atwood likes skoda ║26101 ║
║ 64║ Geoff Dalgas is smart but ║56959 ║
╚════╩══════════════════════════════════╩══════╝
This is what i am trying to acheive
Result:
╔════╦══════════════════════════════════╦══════╦══════╦══════╗
║ T1 ║ String1 ║ snr ║bnr ║T2 ║
╠════╬══════════════════════════════════╬══════╬══════╬══════╣
║ 1 ║ Jeff Atwood is good but naughty ║ 5636 ║1323 ║5 ║
║ 2 ║ Geoff Dalgas is bully and fat ║ 148 ║12148 ║34 ║
║ 3 ║ Jeff Atwood likes skoda and hate ║ ║ ║ ║
║ ║ ferrari ║ 101 ║26101 ║73 ║
║ 4 ║ Geoff Dalgas is smart but not ║ ║ ║ ║
║ ║ intelligent ║ 959 ║56959 ║64 ║
╚════╩══════════════════════════════════╩══════╩══════╩══════╝
The only relationship i see is to compare the string1 and string2 (which is partially equal)
This is my syntax:
SELECT table1.T1, table1.String1, table1.snr, table2.bnr,table2.T2 FROM table1 INNER JOIN table2 WHERE table1.string1 LIKE table2.string2
but i get any error that
There is a chance that you may have found a bug in the SQL parser. Please examine your query closely, and check that the quotes are correct and not mis-matched. Other possible failure causes may be that you are uploading a file with binary outside of a quoted text area. You can also try your query on the MySQL command line interface. The MySQL server error output below, if there is any, may also help you in diagnosing the problem. If you still have problems or if the parser fails where the command line interface succeeds, please reduce your SQL query input to the single query that causes problems, and submit a bug report with the data chunk in the CUT section below:
ERROR: C1 C2 LEN: 56 57 770 STR: etc...
If you don't have any wildcard characters in the LIKE argument, it just does an exact string match. You need to add % wildcards:
SELECT table1.T1, table1.String1, table1.snr, table2.bnr,table2.T2
FROM table1
INNER JOIN table2 ON table1.string1 LIKE CONCAT('%', table2.string2, '%')
Try this:
Select ID, String From (
(SELECT t1, string1 FROM table1)
UNION
(SELECT t2,string2 FROM table2)) order by ID;

Groupwise-max on count() with nested subqueries

My head is turning to mush when trying to get this nesting around my head.
So basically I got 2 tables:
Brokers, which is my "user" table:
╔══════════╦════════════╦
║ ID ║ EMAIL ║
╠══════════╬════════════╬
║ 1 ║ 1#email.co ║
║ 2 ║ 2#email.co ║
║ 3 ║ 3#email.co ║
╚══════════╩════════════╝
Houses, which is houses that the users have added. Currently user and house is connected by the email column (I know, makes more sense to do with a ID):
╔══════════╦════════════╦════════════╦
║ ID ║ TYPE ║ EMAIL ║
╠══════════╬════════════╬════════════╬
║ 1 ║ 1 ║ 1#email.co ║
║ 2 ║ 3 ║ 1#email.co ║
║ 3 ║ 2 ║ 1#email.co ║
║ 4 ║ 3 ║ 1#email.co ║
║ 5 ║ 3 ║ 1#email.co ║
║ 6 ║ 2 ║ 1#email.co ║
║ 7 ║ 3 ║ 1#email.co ║
║ 8 ║ 1 ║ 2#email.co ║
║ 9 ║ 1 ║ 2#email.co ║
║ 10 ║ 2 ║ 2#email.co ║
║ 11 ║ 2 ║ 2#email.co ║
║ 12 ║ 3 ║ 2#email.co ║
║ 13 ║ 3 ║ 3#email.co ║
║ 14 ║ 2 ║ 3#email.co ║
║ 15 ║ 3 ║ 3#email.co ║
║ 16 ║ 1 ║ 3#email.co ║
║ 17 ║ 3 ║ 3#email.co ║
║ 18 ║ 2 ║ 3#email.co ║
║ 19 ║ 2 ║ 3#email.co ║
║ 20 ║ 3 ║ 3#email.co ║
╚══════════╩════════════╩════════════╝
Now what I want to do, is that I want to select all brokers that have type 3 as the highest, most popular kind of house added. So for example if house type 3 represents "Apartments", I want to find the brokers that sell apartments as their number one most popular type.
My current query is:
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
INNER JOIN (
SELECT COUNT( * ) AS total, email, type
FROM house
GROUP BY email, type
ORDER BY total DESC
)h ON b.email = h.email
AND h.type = "3"
ORDER BY b.id DESC
Now this only selects the total amount of houses that that broker has for type 3. It does not only select the brokers where type 3 is their most popular type.
Now to do that, I need to use what is called "Groupwise Max". But I can not use max() on a count(*) like:
MAX(COUNT(*)) as max_value
So I guess that what I need to do is to nest my query further with additional subqueries to first count, and then select the max value.
I've been trying to get it right for a while now and I just can't get my head around it. Anyone can help?
EDIT:
Expected Output:
Based on the table above, Broker 1#email.co got:
1 House with Type 1.
2 Houses with Type 2.
4 Houses with Type 3.
Broker 2#email.co got:
2 houses with Type 1
2 houses with Type 2
1 house with Type 3.
Broker 3#email.co got:
1 house with Type 1.
3 houses with Type 2.
4 houses with Type 3.
Since both 1#email.co and 3#email.co is selling House Type 3 most commonly, they should be included in the output. 2#email.co do not sell type 3 as his most popular type, so he should not be included in the result.
So output:
╔══════════╦════════════╦════════════╦
║ ID ║ EMAIL ║ Total ║
╠══════════╬════════════╬════════════╬
║ 1 ║ 1#email.co ║ 4 ║
║ 3 ║ 3#email.co ║ 4 ║
╚══════════╩════════════╝════════════╝
Posting answer without executing, hope this works!
Select a.ID,a.Email,b.Cnt from Brokers as a
inner join (
Select Email,count(ID) as Cnt from Houses where Type =
(Select max(Type) from Houses)
group by Email
) as b on a.Email = b.Email
I can't understand why you need Count()? I think, according to you question ("select all brokers that have type 3") , it doesn't make sense, or do I misunderstand something?
EDIT:
I have done it in SQL SERVER by temporary table and variable
If you can convert it to mysql syntax, your problem will we solved:
SELECT COUNT(*) as total, Email, [Type]
into #tbl3
from house
group by Email, Type
declare #a int
set #a = (select MAX(total) from #tbl3)
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
inner join
(
select * from #tbl3
where total=#a
) h
on h.Email=b.Email and h.Type=3
EDIT: This is MySql syntax which will do your job.
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (
SELECT COUNT(*) as total, Email, Type
from house
group by Email, Type
);
set #a = (select MAX(total) from table2);
SELECT b.id, b.email, h.email, h.type, h.total
FROM brokers b
inner join
(
select * from table2
where total=#a
) h
on h.Email=b.Email and h.Type=3