Using the same table on SELECT and WHERE clause - mysql

Simple case
I have a simple table where one column is the PK of another element of the same table, as follows:
id | something | parent_id
___________|______________|____________
1 | colors | null
2 | red | 1
3 | green | 1
4 | blue | 1
... | ... | ...
Task
I wanted to get all elements that have the parent_id of the element that matches a condition.
Let's suppose the parent element should have something='colors'
Expected Result
id | something | parent_id
___________|______________|____________
2 | red | 1
3 | green | 1
4 | blue | 1
After looking around on StackOverflow I have tried:
SELECT * FROM my_table WHERE
parent_id=(SELECT id FROM my_table WHERE something='colors')
and also:
SELECT * FROM my_table as t1 WHERE
t1.parent_id=(SELECT id FROM my_table as t2 WHERE t2.something='colors')
but I get this error:
Error: You have an error in your SQL syntax
The reason was a missing ; on the previous file that was being merged before mine. The above queries do work...
This is not my field and I know that a "solution"(?) (used by others in the project) could be:
SELECT * FROM my_table WHERE
parent_id=(SELECT id FROM (SELECT * FROM my_table) AS t1 WHERE something='colors')
but I don't really like this
Thanks anyone for the help.
I know we should LIMIT 1 or use IN to prevent errors, I was trying to simplify the sintax as most as I could.

You can get it with a simple JOIN:
SELECT T1.* FROM my_table AS T1
JOIN my_table AS T2 ON T1.parent_id = T2.id
WHERE T2.something='colors';
This technique is known as a SELF JOIN. Here for more details.

use exists
SELECT t1.* FROM table_name t1
WHERE EXISTS(SELECT 1 FROM table_name t2 WHERE t1.id=t2.parent_id)

You can do :
SELECT t.*
FROM table t
WHERE EXISTS(SELECT 1 FROM table t1 WHERE t1.id = t.parent_id AND t1.something = 'colors');

Related

Selecting the Ids of a table where 3 or more column are duplicates

I am trying to select the ids of 3 columns that I have in my table that all contain the same data except for when the first occurrence of the duplicate was inserted. For example my table is as follows:
Select * From Workers
+----+--------+--------+--------------+
| id | name |JobTitle| description |
+----+--------+--------+--------------+
| 1 | john |Plumber |Installs Pipes|
| 2 | mike | Doctor |Provides Meds |
| 3 | john |Plumber |Installs Pipes|
| 4 | john |Plumber |Installs Pipes|
| 5 | mike | Doctor |Provides Meds |
| 6 | mike | Doctor |Provides Meds |
+----+--------+--------+--------------+
What im basically trying to get is the ids of all the duplicates records expect for the lowest or first id where a duplicate has occurred.
SELECT t1.id
From workers t1, workers t2
Where t1.id > t2.Id and t1.name = t2.name and t1.jobTitle = t2.jobTitle and t1.description = t2.description;
The table i am working with had hundred of thousands of records and I have tried the statement above to get the ids i want but due to the size of the table I get the error:
Error Code: 1054. Unknown column 't1.userId' in 'where clause'
I have tried increasing the timeout in workbench but to no avail.
In this example I am basically trying to get all the ids except for 1 and 2. I thought the above query would have got me what i was looking for but this has not been the case and now I am not sure what else to try.
Any help is greatly appreciated. Thanks in advance.
You can do it with an 'INNER JOIN
SELECT DISTINCT t1.*
From workers t1
INNER JOIN workers t2 ON t1.name = t2.name and t1.jobTitle = t2.jobTitle and t1.description = t2.description
Where t1.id > t2.Id ;
But i can't figure out how you got your message, there is no userid in sight
The error message does not match your query (there is no userId column in the query) - and it is not related to the size of the table.
Regardless, I would filter with exists:
select w.*
from workers w
where exists (
select 1
from workers w1
where
w1.name = w.name
and w1.jobTitle = w.jobTitle
and w1.description = w.description
and w1.id < w.id
)
For performance, consider an index on (name, jobTitle, description, id).

SQL IN (SELECT statement) where the matched SELECT statement is an array, is this possible?

I have two databases that I'd like to match results against. One of them has a column that stores an array of information to be matched with another table.
table1
------------------------------------
| collection_id | items_array |
------------------------------------
| 123 | ['item1' ,'item2'] |
------------------------------------
table2
---------------------
| user_id | item_id |
---------------------
| 2 | item1 |
| 1 | item2 |
---------------------
I'd like to make an SQL query that will use the table1.collection_id to get the table1.items_array column, then get each table2.user_id where the table2.item_id is in the table1.items_array array. My expression right now is (in PDO):
SELECT
table2.user_id
FROM table2
WHERE table2.item_id IN (
SELECT table1.items_array
FROM table1
WHERE table1.collection_id = ?
)
So the idea is that the IN statement should come out to be the array from items_array column. However, this is not working. I've tried formatting the array in the items_array column differently to see if it is a syntax error. I've tried the following:
['item1', 'item2']
['item1','item2']
'item1', 'item2'
But none of them seem to get the intended result.
Is it even possible to do what I'm hoping to do or should I seek at storing the information a different way? I'd like to store it as an array because once the array is placed, the user will never have to update or match against the array again, so I don't think there will be a normalization issue.
Try below query
SELECT #items := items_array FROM table1 WHERE collection_id = 123;
SELECT table2.user_id
FROM table2
WHERE table2.item_id IN ( #items );
Try to use Like instead of IN.
with table2 as
(
select item_id ='item1' union select 'item2' union select 'item3' union select 'item4'
)
select item_id from table2 where item_id like '%' +
(
select items_array from
(
select items_array = '[''item1'',''item2'']'
) table1
)

SQL - select rows that have the same value in two columns

The solution to the topic is evading me.
I have a table looking like (beyond other fields that have nothing to do with my question):
NAME,CARDNUMBER,MEMBERTYPE
Now, I want a view that shows rows where the cardnumber AND membertype is identical. Both of these fields are integers. Name is VARCHAR. Name is not unique, and duplicate cardnumber, membertype should show for the same name, as well.
I.e. if the following was the table:
JOHN | 324 | 2
PETER | 642 | 1
MARK | 324 | 2
DIANNA | 753 | 2
SPIDERMAN | 642 | 1
JAMIE FOXX | 235 | 6
I would want:
JOHN | 324 | 2
MARK | 324 | 2
PETER | 642 | 1
SPIDERMAN | 642 | 1
this could just be sorted by cardnumber to make it useful to humans.
What's the most efficient way of doing this?
What's the most efficient way of doing this?
I believe a JOIN will be more efficient than EXISTS
SELECT t1.* FROM myTable t1
JOIN (
SELECT cardnumber, membertype
FROM myTable
GROUP BY cardnumber, membertype
HAVING COUNT(*) > 1
) t2 ON t1.cardnumber = t2.cardnumber AND t1.membertype = t2.membertype
Query plan: http://www.sqlfiddle.com/#!2/0abe3/1
You can use exists for this:
select *
from yourtable y
where exists (
select 1
from yourtable y2
where y.name <> y2.name
and y.cardnumber = y2.cardnumber
and y.membertype = y2.membertype)
SQL Fiddle Demo
Since you mentioned names can be duplicated, and that a duplicate name still means is a different person and should show up in the result set, we need to use a GROUP BY HAVING COUNT(*) > 1 in order to truly detect dupes. Then join this back to the main table to get your full result list.
Also since from your comments, it sounds like you are wrapping this into a view, you'll need to separate out the subquery.
CREATE VIEW DUP_CARDS
AS
SELECT CARDNUMBER, MEMBERTYPE
FROM mytable t2
GROUP BY CARDNUMBER, MEMBERTYPE
HAVING COUNT(*) > 1
CREATE VIEW DUP_ROWS
AS
SELECT t1.*
FROM mytable AS t1
INNER JOIN DUP_CARDS AS DUP
ON (T1.CARDNUMBER = DUP.CARDNUMBER AND T1.MEMBERTYPE = DUP.MEMBERTYPE )
SQL Fiddle Example
If you just need to know the valuepairs of the 3 fields that are not unique then you could simply do:
SELECT concat(NAME, "|", CARDNUMBER, "|", MEMBERTYPE) AS myIdentifier,
COUNT(*) AS count
FROM myTable
GROUP BY myIdentifier
HAVING count > 1
This will give you all the different pairs of NAME, CARDNUMBER and MEMBERTYPE that are used more than once with a count (how many times they are duplicated). This doesnt give you back the entries, you would have to do that in a second step.

mysql small count issue on same table

Please find db structure as following...
| id | account_number | referred_by |
+----+-----------------+--------------+
| 1 | ac203003 | ac203005 |
+----+-----------------+--------------+
| 2 | ac203004 | ac203005 |
+----+-----------------+--------------+
| 3 | ac203005 | ac203004 |
+----+-----------------+--------------+
I want to achieve following results...
id, account_number, total_referred
1, ac203005, 2
2, ac203003m 0
3, ac203004, 1
And i am using following query...
SELECT id, account_number,
(SELECT count(*) FROM `member_tbl` WHERE referred_by = account_number) AS total_referred
FROM `member_tbl`
GROUP BY id, account_number
but its not giving expected results, please help. thanks.
You need to use table aliases to do this correctly:
SELECT id, account_number,
(SELECT count(*)
FROM `member_tbl` t2
WHERE t2.referred_by = t1.account_number
) AS total_referred
FROM `member_tbl` t1;
Your original query had referred_by = account_number. Without aliases, these would come from the same row -- and the value would be 0.
Also, I removed the outer group by. It doesn't seem necessary, unless you want to remove duplicates.
One idea is to join the table on itself. This way you can avoid the subquery. There might be performance gains with this approach.
select b.id, b.account_number, count(a.referred_by)
from member_tbl a inner join member_tbl b
on a.referred_by=b.account_number
group by (a.referred_by);
SQL fiddle: http://sqlfiddle.com/#!2/b1393/2
Another test, with more data: http://sqlfiddle.com/#!2/8d216/1
select t1.account_number, count(t2.referred_by)
from (select account_number from member_tbl) t1
left join member_tbl t2 on
t1.account_number = t2.referred_by
group by t1.account_number;
Fiddle for your data
Fiddle with more data

single sql statement help

+----+--------+--------+
| id | name | parent |
+----+--------+--------+
| 1 | AA | 0 |
| 2 | AB | 1 |
+----+--------+--------+
How do I get the name of id 1 given that I have the id 2 in one sql statement?
i.e. Rather than selecting the parent then doing another select to get the name from that id.
To clarify, I have the id of 2 and I need to get the name of its parent.
I'm sure this is very simple - I just can't work it out!
Something like this: (haven't tested obviously)
SELECT second.name
FROM
TableName first Join TableName second
ON first.parent = second.id
where first.id = 1
SELECT
T1.name Child, T2.name Parent
FROM
Table T1
LEFT JOIN
Table T2 ON T1.parent = T2.id
WHERE
T1.id = 1
If the hierarchy is always up to 1-level deep in your application, you may as well do:
SELECT `name`
FROM `TableA`
WHERE `id` = (SELECT `parent_id`
FROM `TableA`
WHERE `id` = 2
);
By one-level deep it means that relationships like 1 (is-parent-of) 2 (is-parent-of) 3 does not exist.
However if there can be N-level hierarchy, queries from Yochai Timmer and Parkyprg are just fine.