Finding the next available value in MySQL - mysql

I have a database table products with the following columns.
ID | segment_key | segment_value
1 | Mo | 1
2 | Mo | 3
4 | Jo | 1
5 | Jo | 2
6 | Ta | 1
For any given key I need to find the next available segment_value for me to record in the same table.
ie. for the following segment_key list, the expected outputs are
Mo -> 2
Jo -> 3
Ta -> 2
Ji -> 1
I tried the solution mentioned here but I cannot seem to get the right output.
This is my failed attempt.
SELECT t1.segment_value
FROM products t1
WHERE NOT EXISTS (
SELECT *
FROM products t2
WHERE t2.segment_value = t1.segment_value + 1 and t2.segment_key='Mo' and t2.is_active=1
)
LIMIT 1

You can try to use CTE RECURSIVE to get the gap of all values. then do CROSS JOIN fill in the gap of value from each segment_key.
Final using OUTER JOIN and filter segment_key IS NULL which represent the gap of values
Query #1
WITH RECURSIVE CTE AS(
SELECT MIN(segment_value) val,MAX(segment_value) + 1 max_val
FROM products
UNION ALL
SELECT val + 1 ,max_val
FROM CTE c
WHERE val + 1 <= max_val
)
SELECT c.segment_key,MIN(val) segment_value
FROM (
SELECT DISTINCT val,segment_key
FROM CTE
CROSS JOIN products
) c
LEFT JOIN products p
ON c.val = p.segment_value AND c.segment_key = p.segment_key
WHERE p.segment_key IS NULL
GROUP BY c.segment_key;
segment_key
segment_value
Mo
2
Jo
3
Ta
2
View on DB Fiddle

Related

How to prevent duplication on the second table Using inner Joins and the Count

SELECT T.column_11,
count(column_11) count
FROM wp_tablesome_table_4695 T
JOIN wp_fea_submissions S ON T.column_2 = S.title
group BY T.column_11
wp_tablesome_table_4695
column 2 | column 11
1 | location 1
2 | location 2
3 | Location 3
wp_fea_submissions
title
1
1
2
3
Result
column 11| count
1 | 2
2 | 1
3 | 1
The count result is also counting the duplicate S.Title how to prevent counting the Duplicate
The count need to be done inside a subquery.
SELECT T.column11,
count(column11) count
FROM wp_tablesome_table_4695 T
INNER JOIN (select distinct title
from wp_fea_submissions
) S ON T.column2 = S.title
group BY T.column11;
Or
with cte as ( select distinct title
from wp_fea_submissions
) select wp.column11, count(wp.column11) as cnt
from cte
inner join wp_tablesome_table_4695 wp on wp.column2=cte.title
group by wp.column11;
https://dbfiddle.uk/iVprcr8z

Sum hours value, count and display based on hours using SQL

I have 2 tables which are Teacher and Activities.
CREATE TABLE teacher (
TeacherId INT, BranchId VARCHAR(5));
INSERT INTO teacher VALUES
("1121","A"),
("1132","A"),
("1141","A"),
("2120","B"),
("2122","B");
CREATE TABLE activities (
ID INT, TeacherID INT, Hours INT);
INSERT INTO activities VALUES
(1,1121,2),
(2,1121,1),
(3,1132,1),
(4,1141,NULL),
(5,2120,NULL),
(6,2122,NULL);
NULL indicates no activities and will be convert to 0 on output table. I want to produce a query to count total of hours and count how many activities base on teacher hours such as the following table:
+-----------+------------+------------+
| Hours | A | B |
+-----------+------------+------------+
| 0 | 1 | 2 |
| 1 | 1 | 0 |
| 2 | 0 | 0 |
| 3 | 1 | 0 |
+-----------+------------+------------+
Edited: Sorry I don't know how to elaborate accurately, but here is the fiddle i received from other member https://www.db-fiddle.com/f/mmtuZquKyUqdhPvTFN9qaF/1
Edit: Last, modification need, to sum the hours and count the hours base on branch id and teacher id as the output.
Expected output here (red text): https://drive.google.com/file/d/1wyZ_aX5hz_7I1Ncf5sXLpstYk6FT8PMg/view?usp=sharing
We can handle this via the use of a calendar table of hours joined to an aggregation subquery:
SELECT
t1.Hours,
SUM(CASE WHEN t2.BranchId = 'A' THEN t2.cnt ELSE 0 END) AS A,
SUM(CASE WHEN t2.BranchId = 'B' THEN t2.cnt ELSE 0 END) AS B
FROM (SELECT 0 AS Hours UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t1
LEFT JOIN
(
SELECT t.BranchId, COALESCE(a.Hours, 0) AS Hours, COUNT(*) AS cnt
FROM Teacher t
LEFT JOIN Activities a ON a.TeacherId = t.TeacherId
GROUP BY t.BranchId, COALESCE(a.Hours, 0)
) t2
ON t1.Hours = t2.Hours
GROUP BY
t1.Hours
ORDER BY
t1.Hours
Demo
This is basically a JOIN and aggregation . . . but you need to start with all the hours you want:
SELECT h.Hours,
COALESCE(SUM(t.BranchId = 'A'), 0) AS A,
COALESCE(SUM(t.BranchId = 'B'), 0) AS B
FROM (SELECT 0 AS Hours UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
) h LEFT JOIN
activities a
ON h.hours = COALESCE(a.hours, 0) LEFT JOIN
teacher t
ON t.TeacherId = a.TeacherId
GROUP BY h.Hours
ORDER BY h.Hours;
Here is a db<>fiddle.

MySQL multiple SubQueries on same table

I got a table votes that indicates me if a user voted for a specific movie. It also shows me how many movies a user has voted for.
id_film | id_user | voting
----------------------------
1 | 1 | 7
1 | 33 | 5
3 | 1 | 9
4 | 7 | 7
4 | 2 | 8
4 | 1 | 6
6 | 1 | 6
... | ... | ...
I want to get a list of id_film's which are related to id_user's in this way:
Get all id_film's from a specific id_user like
SELECT id_film FROM votes WHERE id_user = 1
Grab every id_user which is related
SELECT DISTINCT v.user FROM votes v WHERE id_film IN ( id_film's )
Then SELECT id_film's FROM votes v WHERE user IN ( "user list from previous query" ) except id_film's from first query.
This was my first attempt:
SELECT id_film, film.title, film.originaltitle, COUNT(*)
FROM votes v
INNER JOIN film ON v.id_film = film.id
WHERE user IN
(
SELECT DISTINCT v.user
FROM votes v
WHERE id_film IN
(
SELECT id_film
FROM votes v
WHERE user = 1
)
)
AND
id_film NOT IN
(
SELECT id_film
FROM votes v
WHERE user = 1
)
GROUP BY id_film
It doesn't work. MySQL took too long for a result and I restarted XAMPP.
So I tried another SELECT, this time with JOINS:
SELECT DISTINCT v.id_film AS vFilm, v1.user AS v1User, v2.id_film AS v2Film
FROM votes v
LEFT OUTER JOIN votes v1 ON v1.id_film = v.id_film
LEFT OUTER JOIN votes v2 ON v1.user = v2.user
WHERE v.user = 1
AND v1.user != 1
AND v2.id_film NOT
IN
(
SELECT id_film
FROM votes
WHERE user = 1
)
GROUP BY v2.id_film
Also doesn't work, but when I tried it without the NOT IN condition in the end it works! (It took appr. 13 sec.) :-(
Here is the working query.
SELECT DISTINCT v2.id_film AS v2Film
FROM votes v
LEFT OUTER JOIN votes v1 ON v1.id_film = v.id_film
LEFT OUTER JOIN votes v2 ON v1.user = v2.user
WHERE v.user = 1
AND v1.user != 1
With Output
v2Film
---------
1
13
14
58
4
...
But this query doesn't except id_film's from first query.
Because I know that user 1 already voted for id_film 1.
So, am I totally wrong with my logic or is my code too complex for this?

group by over three elements to display all possible combinations

I have three tables as following and I try to group by over three elements to display all possible combinations
Play
--------------------------------
id typeId periodId
--------------------------------
1 a 1
2 b 1
3 b 1
4 b 1
5 a 2
6 b 1
7 a 1
8 b 2
Period
-------------
periodId
-------------
1
2
3
Type
-------------
typeId
-------------
a
b
c
I tried this but it doesn't work, I see some NULL values but the group by doesn't work.
SELECT type, p, count(*) as superNiceCount
FROM Play
RIGHT JOIN Period pp ON Play.periodId = Period.periodId
RIGHT JOIN Type tt ON Play.typeId = Type.typeId
GROUP BY tt.typeId, pp.periodId
The expected result would be
-------------------------
type p superNiceCount
-------------------------
a 1 2
a 2 1
a 3 0
b 1 4
b 2 1
b 3 0
c 1 0
c 2 0
c 3 0
How may I achieve that ?
see if this works
SELECT ty.typeId as type, pe.periodId as p, count(pl.id) as superNiceCount
FROM Period pe
CROSS JOIN Type ty
LEFT JOIN Play pl ON (pl.periodId = pe.periodId AND pl.typeId = ty.typeId)
GROUP BY ty.typeId, pe.periodId
if not try
SELECT ty.typeId as type, pe.periodId as p, count(pl.id) as superNiceCount
FROM (
SELECT * FROM
Period pe
CROSS JOIN Type ty
) as t1
LEFT JOIN Play pl ON (pl.periodId = t1.periodId AND pl.typeId = t1.typeId)
GROUP BY ty.typeId, pe.periodId

MySQL 3 column query return duplicates

x_Id | y_Id | z_Id
----- |----- |-----
1 | 1 | 1
2 | 1 | 1
3 | 1 | 1
4 | 1 | 1
5 | 1 | 1
1 | 2 | 3
I am relatively new at programming and I cant figure out this MySql query. I need to select x_Id only where ((y_Id = 1 AND z_Id = 1) AND (y_Id = 2 AND z_Id = 3)).
Therefore, using these numbers as an example the only thing that should be selected is (x_Id =) 1.
**All of these columns are in the same table
The closest I have come is by using this query:
SELECT
*
FROM
`relationships`
WHERE
y_id = 1 AND
z_id = 1
UNION
SELECT
*
FROM
`relationships`
WHERE
z_id = 3 AND
y_id = 2
However, this returns all the x_ids and x_id = 1 again as a duplicate.
**I am using sqlPro and MySql 5
no need to Union.
Updated after seeing comments:
select
*
from relationships T1
INNER JOIN relationshipsT2 on t1.x_Id = t2.x_Id where
((T1.y_Id = 1 AND T1.z_Id = 1) AND (T2.y_Id = 2 AND T2.zz_Id= 3))
also you can only return x_Id instead of *
If you are only interested in the x_id value you can use the query above, but just add DISTINCT and project only the x_id value.
Example:
SELECT
DISTINCT x_id
FROM
`relationships`
WHERE
y_id = 1 AND z_id = 1
UNION
SELECT
DISTINCT x_id
FROM
`relationships`
WHERE
z_id = 3 AND y_id = 2
There are few other way how to do it, which are even easier such as use OR in the WHERE clause.
Updated after seeing comments:
Using an aggregate SUM() you can total up the number of conditions met per value of x_id. If the total is > 1, both conditions are met somewhere in the table.
SELECT DISTINCT x_id FROM (
SELECT
x_id,
SUMCASE WHEN (y_id = 1 AND z_id = 1) OR (z_id = 3 AND y_id = 2) THEN 1 ELSE 0 END) AS hasboth
FROM relationships
GROUP BY x_id
HAVING hasboth > 1
) subq