Show repeated values on a simple MySQL query - mysql

Having this two users:
id = 143 user = User 1
---- id = 91 user = User 2
and this simple query:
SELECT name FROM users where id IN (143,143,91);
It two results:
User 1
User 2
Is there any way to return the repeated values as well? My desired output would be:
User 1
User 1
User 2

I think what you want is UNION ALL:
SELECT name FROM users where id = 143
UNION ALL
SELECT name FROM users where id = 143
UNION ALL
SELECT name FROM users where id = 91
One simple query will do not return the same 143 twice.

As far as I know, creating another table inserting all the ID you want to extract:
CREATE TABLE TUSERS (ID INT, NAME VARCHAR(20));
INSERT INTO TUSERS VALUES (91, 'User2');
INSERT INTO TUSERS VALUES (143, 'User1');
CREATE TABLE TMP01 (ID INT);
INSERT INTO TMP01 VALUES(143);
INSERT INTO TMP01 VALUES(143);
INSERT INTO TMP01 VALUES(91);
SELECT A.*
FROM TUSERS A
RIGHT JOIN TMP01 B ON A.ID=B.ID;
Output:
ID NAME
143 User1
143 User1
91 User2

The IN list is simply used for filtering existing rows. If you want all values, then an outer join is recommended. You can produce the IN list on the fly:
select u.name
from (select 143 as id union all
select 143 union all
select 91
) ids left join
users u
on u.id = i.id;

Related

How to transform this SQL query to query with GROUP BY and HAVING?

There're products, products_filters, filters_values tables in DB.
products_filters references to products table via product_id column which is a foreign key.
Also products_filters references to filters_values table via filter_value_id column which is also a foreign key
When user selects filters, SQL query which extracts all ids of suitable products is formed.
For example, chosen filters are:
Sex: Male, Female
Brand: Brand1, Brand2, Brand3
How it should work:
It needs to select all products which have filter Sex set to Male OR Female AND filter Brand set to Brand1 OR Brand2 OR Brand3. But products having matching only in one of the chosen filter category either Sex or Brand, must not be selected. It necessiraly to have matching in all selected categories.
I think SQL should look like this:
SELECT product_id FROM products_filters WHERE
(filter_value_id = 1 OR filter_value_id = 2)
AND
(filter_value_id = 3 OR filter_value_id = 4 OR filter_value_id = 5)
Where 1 is Male, 2 is Female, 3 is Brand1, 4 is Brand2, 5 is Brand3.
But this query doesn't work.
In my previous question I was answered that GROUP BY and HAVING may help.
Q: How can I transform SQL above with GROUP BY and HAVING?
Given
drop table if exists t;
create table t(id int ,gender varchar(1), brand varchar(1));
insert into t values
(1,'m',1),(1,'f',2),(1,'m',3),(2,'f',1),(2,'f',2),(2,'f',3),
(3,'m',1),(4,'f',2);
Correlated sub queries with distinct
select distinct id
from t
where
(select count(distinct gender) from t t1 where gender in('m','f') and t1.id = t.id) = 2 and
(select count(distinct brand) from t t1 where brand in(1,2,3) and t1.id = t.id) = 3
;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.002 sec)
SELECT product_id
FROM products_filters AS f1
JOIN products_filters AS f2 USING(product_id)
WHERE f1.filter_value_id IN (1,2)
AND f2.filter_value_id IN (3,4,5)
(I don't think GROUP BY...HAVING COUNT(*) = 2 is reasonable for this case.)
(The EAV schema design is a pain to deal with.)

How to get Database-table entries where a certain column is not linked to a certain value by another table?

I have a database with the following tables: Students, Classes, link_student_class. Where Students contains the information about the registered students and classes contains the information about the classes. As every student can attend multiple classes and every class can be attended by multiple students, I added a linking-table, for the mapping between students and classes.
Linking-Table
id | student_id | class_id
1 1 1
2 1 2
3 2 1
4 3 3
In this table both student_id as well as class_id will appear multiple times!
What I am looking for, is a SQL-Query that returns the information about all students (like in 'SELECT * FROM students') that are not attending a certain class (given by its id).
I tried the following SQL-query
SELECT * FROM `students`
LEFT JOIN(
SELECT * FROM link_student_class
WHERE class_id = $class_id
)
link_student_class ON link_student_class.student_id = students.student_id
Where $class_id is the id of the class which students i want to exclude.
In the returned object the students i want to include and those i want to exclude are different in the value of the column 'class_id'.
Those to be included have the value 'NULL' whereas those I want to exclude have a numerical value.
NOT EXISTS comes to mind:
select s.*
from students s
where not exists (select 1
from link_student_class lsc
where lsc.student_id = s.student_id and
lsc.class_id = ?
);
The ? is a placeholder for the parameter that provides the class.
you should check for NULL link_student_class.student_id
SELECT *
FROM `students`
LEFT JOIN(
SELECT *
FROM link_student_class
WHERE class_id = $class_id
) link_student_class ON link_student_class.student_id = students.student_id
where link_student_class.student_id is null
Or also a NOT IN predicate:
WITH
stud_class(id,stud_id,class_id) AS (
SELECT 1, 1,1
UNION ALL SELECT 2, 1,2
UNION ALL SELECT 3, 2,1
UNION ALL SELECT 4, 3,3
)
,
stud(stud_id,fname,lname) AS (
SELECT 1,'Arthur','Dent'
UNION ALL SELECT 2,'Ford','Prefect'
UNION ALL SELECT 3,'Tricia','McMillan'
UNION ALL SELECT 4,'Zaphod','Beeblebrox'
)
SELECT
s.*
FROM stud s
WHERE stud_id NOT IN (
SELECT
stud_id
FROM stud_class
WHERE class_id= 2
);
-- out stud_id | fname | lname
-- out ---------+--------+------------
-- out 3 | Tricia | McMillan
-- out 4 | Zaphod | Beeblebrox
-- out 2 | Ford | Prefect
-- out (3 rows)
-- out
-- out Time: First fetch (3 rows): 9.516 ms. All rows formatted: 9.550 ms

Adding a row if it does not exist in a MySQL table

Inside a table there are 2 columns: userid and roleid. Every user should atleast have roleid 4 . There are currently around 10.000 records, but somehow a small amount of users do not have this role.
Visual example:
userid | roleid
1 1
1 4
2 1
2 4
3 1 <---------- userid 3 misses roleid 4!
4 1
4 4
Is it possible to execute a query and add a row with the userid and roleid when that combination does not exist?
Yes.
insert into userRoles(userid, roleid)
select userid, 4
from userRoles
group by userid
having sum(roleid = 4) = 0;
The sum(role = 4) in the having clause counts the number of rows for each user that have 4. The = 0 says there are none.
Note: This gives all users in this table a role id of 4. There may be users with no roles at all.
If you want them, then use the users table:
insert into userRoles(userid, roleid)
select u.userid, 4
from users u
where not exists (select 1 from userRoles ur where ur.userid = u.userid);
You should search for user that have not 4 in roleID
insert into yourTable ( userId, roledid)
select userid, 4
from yourTable
where roleid <>4

How to merge results of two select statements into one table with two columns?

I have two SELECT statements. Both give me the same amount of rows and the values relate to each other.
SELECT testtime
FROM testinspection
WHERE sample_id = (
SELECT id
FROM sample
WHERE name = '12_1')
SELECT image
FROM testedsampleimage
WHERE id in (
SELECT testedsampleimage_id
FROM testinspection
WHERE sample_id = (
SELECT id
FROM sample
WHERE name = '12_1'))
So in my example I have a test image for a specific test time and I want to have both results in one table, like this (for example):
TESTTIME | IMAGE
-------------------
15 | <LONG>
63 | <LONG>
78 | <LONG>
25 | <LONG>
12 | <LONG>
Does anybody know how to do this?
SELECT t.testtime,i.image
FROM sample s
join testinspection t on t.sample_id = s.id
join testedsampleimage i on t.testedsampleimage_id = i.id
WHERE s.name = '12_1'
It seems there is a 1-1 relation between the two tables based on id, testedsampleimage_id fields. In this case you can use a simple JOIN operation:
SELECT testtime, image
FROM testinspection
JOIN testedsampleimage ON id = testedsampleimage_id
WHERE sample_id = (
SELECT id
FROM sample
WHERE name = '12_1')
You should use union for combining result of two select statement.
SELECT testtime
FROM testinspection
WHERE sample_id = (
SELECT id
FROM sample
WHERE name = '12_1')
UNION ALL
SELECT image
FROM testedsampleimage
WHERE id in (
SELECT testedsampleimage_id
FROM testinspection
WHERE sample_id = (
SELECT id
FROM sample
WHERE name = '12_1'))
If you want to remove duplicate values then use only UNION instead of UNION ALL.

How to get ID for INSERT if name already used, else generate new one

I'm having a bit of trouble with an INSERT query.
I have a table I'm inserting a value into that's like this:
TABLE cars
ID Brand Model B_ID
---------------------------
1 Ford Escort 1
2 Ford Focus 1
3 Nissan Micra 2
4 Renault Megane 3
5 Ford Mustang 1
ID is unique and B_ID is the same ID for every same brand.
When inserting a new entry I want to be able to check if a brand is already in there and use that same B_ID otherwise I want to increment the highest B_ID and insert that.
I've got this far:
INSERT INTO 'cars' ('brand', 'model', 'B_ID')
VALUES (
'Nissan'
'Note'
'SELECT B_ID FROM cars WHERE brand = 'Nissan'
)
How can I get the highest B_ID and increment it by one if there is no match with my subquery because it's a new brand?
I'm using MySQL.
INSERT INTO `cars` (`brand`, `model`, `B_ID`)
select 'Nissan', 'Note', coalesce(Max(B_ID),0)+1 FROM cars WHERE brand = 'Nissan'
Until you normalize your tables:
INSERT INTO cars
(brand, model, B_ID)
SELECT 'Nissan'
, 'Note'
, COALESCE( ( SELECT B_ID
FROM cars
WHERE brand = 'Nissan'
LIMIT 1
)
, ( SELECT MAX(B_ID)
FROM cars
) + 1
, 1 --- this is for the case when the table is empty
)
Also notice that if you have multiple concurrent INSERT, you may end with rows that have different brand but same B_ID.