SELECT where with multiple conditions in ONE query - mysql

There are two things I want to achieve.
This is my database table called "table".
id | friend
---|--------
1 | null
2 | 1
3 | 0
4 | 3
5 | 3
6 | null
There are two SELECT queries I want to do.
$id = 3;
SELECT * FROM table WHERE id = $id; // Not sql injection safe, just an example
This should select row id = 3. If that row's friend column = 0, then:
SELECT rows WHERE friend = $id.
If that row's friend column is something other than 0, then just return that row, row 3. But since my table above shows that row id 3's friend column = 0, this should altogether return rows: 3, 4, 5.
Also, another scenario a something a little different:
$id = 5;
SELECT * FROM table WHERE id = $id;
If that row's friend column <> (does NOT equal) 0 AND IS NOT NULL, then use the friend number and:
SELECT * WHERE id = friend from previous table.
In this example, it will return rows 3, 4, 5 because ID = 5 and the friend ID of 5 is 3. So we search columns id AND friend for 3 and we select it.
I want to combine all of those together into one MySQL SELECT query. How can I do that?
Any help will be appreciated!

In the first scenario, I don't understand exactly why a zero value for friend returns 3, 4, and 5. Why not 2? I'm assuming that if the friend value is zero, then add the rows which have you as a friend.
So, before this first example, I cannot stand a table named "table", so I will use friends as the name of the table.
SELECT FF.id
FROM friends FF
INNER JOIN friends FID on FF.friend = FID.id
WHERE FID.friend = 0 AND FID = $id
UNION
SELECT F2.id FROM friends F2 WHERE F2.id = $id AND F2.friend IS NOT NULL
The inner join, takes the id of friends (FID.id) and joins on the the friends table again to get all the records with that as a friend (FF.friend) value.
Then UNION will include the original id. Both sides of the UNION will return no results if the friend field is NULL.
Similarly for the second scenario, use the given value, ($id = 5), find that record's friend value, and query for all records with that as a friend, then union its record.
SELECT FF.id
FROM friends FF
WHERE FF.friend = (SELECT FIN.friend FROM friends FIN where FIN.id = $id)
UNION
SELECT FIN.friend FROM friends FIN where FIN.id = $id

Related

Combine two SELECT queries together by using value from SELECT in WHERE

id | number
---|--------
1 | null
2 | 1
3 | null
4 | 0
5 | 4
6 | 4
This is what I want to do this in one query. How can I combine both of these queries together?
$id = 4;
SELECT * FROM users WHERE id = $id OR number = $id
// This will return rows 4,5,6
2nd query:
$id = 5;
SELECT * FROM users WHERE id = $id AND id = $numberColumnOfId AND number = $numberOfColumnId;
// This will return rows 4,5,6
$numberColumnOfId is the number of the $id. So if the $id = 5, then the number would be 4. So select rows where ID = 5.
How can I combine both of the SELECT statements together?
Use two queries that you combine with UNION.
The first query gets the rows with the given $id, the second query gets the ones that match via thenumber` column.
SELECT *
FROM users
WHERE id = $id OR number = $id
UNION
SELECT u1.*
FROM users AS u1
JOIN users AS u2 ON u1.number = u2.number OR u1.id = u2.number
WHERE u2.id = $id or u2.number = $id
DEMO

MySQL query to find ids that do not exist in table

I have a list of ids pre-generated that I need to check if exist in a table. My table has two columns, id, name, where id is an auto increment integer and name is a varchar(255).
I basically want to get a count of how many ids do not exist in table foo from my pre-generated list. So say my list has the numbers 5 and 10 in it, what's the best way to write something to the extent of:
select count(*) from foo where id does not exist in ( 5, 10 )
The idea here is that if 5 and 10 do not exist, I need the response 2, and not the number of rows in foo that do not have the id 5 or 10.
TL; DR sample data and queries at rextester
The idea here is that if 5 and 10 do not exist, I need the response 2, and not the number of rows in foo that do not have the id 5 or 10.
You should have provided a little more information to avoid confusion.
Example
id | name
1 | tom
2 | joe
3 | mae
4 | goku
5 | vegeta
If your list contains (1, 2, 3) then your answer should be 0 (since all three are in the table )
If your list contains (1, 2, 6) then your answer should be 1. ( since 1 and 2 are in the table but 6 is in't )
If your list contains (1, 6, 7) then your answer should be 2.
If your list contains (6, 7, 8) then your answer should be 3.
assuming this was your question
If you know the length of your list
select 2 - count(*) as my_count from foo where id in (5, 10)
The following query tells you how many are present in foo.
select count(*) from foo where id in (5,10)
So if you want to find those that do not exist, subtract this result from the length of your list.
select n - count(*) as my_count from foo where id in (5, 10,....)
You could use on fly table using union and the a left join
select count(*)
from my_table as m
left join (
select 5 as id from dual
union
select 10 from dual ) t on t.id = m.id
where t.id is null
otherwise you can populate a tempo table with the value you need and use left join
where the value is null

Return set(s) ID only if all items from that set meet a certain criteria

I have looked at similar questions, but I can't seem to wrap my head around how the answers work in order to apply them to my case.
I have sets of articles (set_table)
ID SET ID ART
1 1
1 4
2 1
2 4
3 2
1 3
Those articles have a table with their parent ID. (article_table)
ID ART ID PARENT
1 1
2 3
3 2
4 1
Then those parents have a condition they have to meet, but it could be multiple (parent_table):
PARENT ID GROUP ID
1 6
2 15
3 12
Meaning, I have to select all sets whose articles (all of them) are in GROUP 6, then the result should be ID SET: 2. Or I could need to select all sets whose articles (all of them) are in GROUPS 6 and 15, then the result should be ID SET: 1. Or I could need to select all sets whose articles (all of them) are in GROUPS 6, 12; then the result should be NULL.
I have tried:
SELECT parent_id
FROM parent_table
WHERE group_id IN (6,15)
GROUP BY parent_id
HAVING COUNT(DISTINCT group_id) = 2; -- Number of group ids
Which is cool, but I don't manage to filter the sets correctly, my attempts in selecting the set are not working.
The query below is not so painful once you start writing it. Just join together the three tables, and then use conditional aggregation to count the number of entries in an ID_SET which have the desired groups.
The following query finds the ID_SET values which have groups of either 6 or 12. Note that this will return an empty result set for the sample data you gave in your original question. The DISTINCT subquery is needed to remove duplicates group values which would otherwise throw off the conditional aggregation.
SELECT t.ID_SET,
SUM(CASE WHEN t.GROUP_ID IN (6, 12) THEN 1 ELSE 0 END) AS groupCount
FROM
(
SELECT DISTINCT s.ID_SET, p.GROUP_ID
FROM set_table s
INNER JOIN article_table a
ON s.ID_ART = a.ID_ART
INNER JOIN parent_table p
ON a.ID_PARENT = p.PARENT_ID
) t
GROUP BY t.ID_SET
HAVING groupCount = 2 -- change 2 to however many group values you want to match
Use the below query
select ID ART
from articles a
join Parent1 p1 on a.ID ART = p1.ID ART
join Parent2 p2 on p1.ID PARENT = p2.PARENT ID AND p2.GROUP ID in (6,12)

Return all products from left table and results from rating table whether a given user rated them or not

I have 332 products in a selection table and would like to return exactly 332 results. Each product has been rated or not by a given user in the matching table. These are the results from two tables using the following query
SELECT a.product_id,a.brand,b.user_id,b.rating,b.comment
FROM selection a
LEFT JOIN matching b ON a.product_id = b.product_id
product_id brand user_id rating comment
1 A & P 30 4.5 NULL
1 A & P 30 4.5 NULL
1 A & P 52 1 NULL
2 A & W 1 3 good flavor
2 A & W 24 5 NULL
I want to return all the products with a rating and comment where user_id = 1 and then the remaining products where user 1 did not rate or comment on the product. I have tried
WHERE user_id = 1 OR
user_id <> 1 AND rating ID NULL and comment IS NULL
This will just return the same as WHERE user_id = 1. I have also tried GROUP BY product_id This returns the correct number of results but not all of the user's ratings or comments were controlled by this alone. Is there a way to define the user that it will select when returning the grouped results? Any other suggestions? Thanks!
If you meant for the WHERE statement to include two separate conditions you need to surround the second statement in parenthesis; otherwise SQL would treat each operator as its own condition:
WHERE user_id = 1 OR
(user_id <> 1 AND rating ID NULL and comment IS NULL)

MYSQL select from table where field is in the field

UPDATED
id | id_list
1 | 2,3,5,7
2 | 1,4,5,6
3 | 1,4,6,7
4 | 2,3,5,8
5 | 1,2,4,8
6 | 2,3,7,8
7 | 1,3,6,9
8 | 4,5,6,9
9 | 7,8
let's say I'm up to the content of id=1
I wanted to select all the rows where id is in id_list of id=1 PLUS the row where id=1
so the result would be
rows with id = 1,2,3,5,7
How to do this query guys?
You can also use a self join
Using IN()
select * from atable a
join atable b on (a.id = b.id )
where 1 IN (a.id_list) or b.id =1
Fiddle with IN()
Using FIND_IN_SET()
select * from atable a
join atable b on (a.id = b.id )
where FIND_IN_SET('1', a.id_list) or b.id =1
Fiddle with FIND_IN_SET()
Using UNION ALL
select * from atable
where id =1
UNION ALL
select * from atable
where 1 IN (id_list)
Fiddle with UNION ALL
Your database design is broken; id_list should be represented as a join table instead of as a string. However, to solve your immediate problem:
select * from table where id=1
or id_list like '1%'
or id_list like '%,1,%'
or id_list like '%,1'
Adjust as needed for PreparedStatement. You have to provide all three cases because if you just did
or id_list like '%1%'
and id_list contained the value 11, you'd get an incorrect match
Try this (see SQL-Fiddle):
SELECT * FROM tbl
WHERE id = 1
OR INSTR((SELECT id_list FROM tbl WHERE id = '1'), id) > 0;
Tested with MySQL 5.5.30
try this one
select *
from tbl
where id=1
or id_list like '%1%'
This appears to call for a union of two sets. The one set would be the single row whose id matches the specified value:
SELECT
id
FROM
atable
WHERE
id = #id
The other set would be the result of this self-join:
SELECT
item.id
FROM
atable AS item
INNER JOIN
atable AS list
ON
FIND_IN_SET(item.id, list.id_list)
WHERE
list.id = #id
That is, the row with the specified id is matched against every row in the table on the condition that the other row's id is found in the specified row's id_list.
You can try the complete query at SQL Fiddle.
Please note that lists aren't a very good design feature. In your situation, it might be better to use a many-to-many table as suggested by #Othman. Only I would probably use a slightly different query to get the desired output, because his doesn't include the specified row itself:
SELECT
id
FROM
manytomany
WHERE
id = #id
UNION
SELECT
linked_id
FROM
manytomany
WHERE
id = #id
;
While the entries in manytomany are assumed to be unique, the query uses the UNION DISTINCT operator because of the potential duplicates returned by the first subquery, although it is possible to move the application of DISTINCT to the first subquery only like this:
SELECT DISTINCT
id
FROM
manytomany
WHERE
id = #id
UNION ALL
SELECT
linked_id
FROM
manytomany
WHERE
id = #id
;
That first subquery could actually be rewritten simply as SELECT #id AS id, but the rewrite would only make sense if the passed value was guaranteed to be valid, i.e. that it would definitely be found in manytomany.id.
Here's a demo for the other approach too (all three variations, including the SELECT #id AS id one).
I don't have an answer for your question but I encourage you to redesign your table like this I think this called many to many relation
id | friend
1 | 2
1 | 3
1 | 5
1 | 7
2 | 1
2 | 4
2 | 5
2 | 6
3 | 1
3 | 4
3 | 6
3 | 7
And then your query will be like this
SELECT DISTINCT(friend) FROM `new` WHERE id = 1
I am assuming you are using php..
My suggestion is to grab the id_list for id 1.
Explode that id_list on the comma, and then do another mysql query to grab the remaining results for 5|3|6|8
ex) $idarray = explode(",", $result);
select * from your_table where id in ('5','3','6','8')
OPTION 2:
SELECT * FROM your_table
WHERE id = '1'
OR id IN ('\''+(SELECT REPLACE(id_list,',','\',\'') FROM your_table WHERE id = '1')+'\'')
EDIT: Oops, sorry, that should be an OR instead.