i am trying to write a query which would show me all records which overlap based on values Valid_From and Valid_To and based on criteria.
This is my sample data:
ID | Valid_From | Valid_To | Block_Type | Valid | Block_ID
1 5 10 a TRUE 1
2 10 15 a TRUE 1
3 6 10 a TRUE 1
4 3 4 a FALSE 1
5 2 4 a FALSE 1
6 1 1 a FALSE 1
7 1 10 b TRUE 1
8 1 10 c TRUE 2
9 1 10 c TRUE 2
10 1 15 b TRUE 1
11 5 10 a TRUE 1
ID is Primary Key with Auto Increment - unique for every record
Block_Type - Type of block - can have more values for every Block_ID example: Block_ID 1 has Block_Type "a" and "b", Block_ID 2 has Block_Type "c", every Block_ID can have any Block_Type, meaning every Block_ID can have Block_Type "a" to "z"
Valid - this just states if Valid_To is bigger than some value, for
testing i set this value to 5
Block_ID - groups multiple records in one Group
For showing what records overlap i use this query:
select a.id, GROUP_CONCAT(b.id) as abcd
from new_table a, new_table b
where a.id <> b.id
and a.Block_ID = b.Block_ID
and a.Block_Type = b.Block_Type
and a.Valid = b.Valid
and ((a.Valid_To between b.Valid_From and b.Valid_To) or (a.Valid_From between b.Valid_From and b.Valid_To)
or (a.Valid_To = b.Valid_From) or (a.Valid_From = b.Valid_To))
group by a.id;
this works fine, it shows me if any records with same Block_Type, same value in Valid and Block_ID overlap, my problem is that this query doesnt show me records which dont overlap (in this example it is record with ID 6) i completely understand why, so i tried to edit my query using case when instead of where but so far i wasnt able to achieve what i want.
This is what my query returns now:
ID | abcd
1 2
2 1,11,3
3 2
4 5
5 4
7 10
8 9
9 8
10 7
11 2
I would like this query to list all records and to list in new column "abcd" all overlaping records, for records that do not overlap i would just like null in the same column, so it would look like this:
ID | abcd
1 2
2 1,11,3
3 2
4 5
5 4
6 null
7 10
8 9
9 8
10 7
11 2
cant you point me in the right direction? What can i change to make it work the way i need?
Thank you very much
If i understand your problem correctly, You need a left join instead of Inner join -
SELECT a.id, GROUP_CONCAT(b.id) AS abcd
FROM new_table a
LEFT JOIN new_table b ON a.id <> b.id
AND a.Block_ID = b.Block_ID
AND a.Block_Type = b.Block_Type
AND a.Valid = b.Valid
AND ((a.Valid_To BETWEEN b.Valid_From AND b.Valid_To)
OR (a.Valid_From BETWEEN b.Valid_From AND b.Valid_To)
OR (a.Valid_To = b.Valid_From)
OR (a.Valid_From = b.Valid_To)
)
GROUP BY a.id;
Related
As the result of the query, I want to get all rows (Drivers), order by the drivers who got most series wins.
If a driver has won 4 tacks at least one or more times but failed to win the remaining track at least once, his series count is 0.
Driver Table
ID|Name| .........
1 A
2 B
3 C
4 D
Tracks Table
TID |FK|Track1_Wins|Track2_Wins| Track3_Wins|Track4_Wins|Track5_Wins|
1 1 5 6 3 2 4
2 2 2 4 0 5 3
3 3 6 3 9 4 7
4 4 5 8 2 4 1
My code sample
SELECT `Drivers`.`Name`, LEAST(`Track1_Wins`, `Track2_Wins`, `Track3_Wins`, `Track4_Wins`, `TRACK5_Wins`) AS Series
FROM `Drivers`, `Tracks`
ORDER BY Series DESC;
Accidently I got part expected output when I use WHERE with Driver ID
SELECT `Drivers`.`Name`, LEAST(`Track1_Wins`, `Track2_Wins`, `Track3_Wins`, `Track4_Wins`, `TRACK5_Wins`) AS Series FROM `Drivers`, `Tracks` WHERE `Drivers`.`ID` = 2 ORDER BY Series DESC;
It will give the expected result but with Same Driver Name as expected
B 3
B 2
B 1
B 0
My expected output is
Name | Series
C 3
A 2
D 1
B 0
Run this,
SELECT d.`Name`,
LEAST(`Track1_Wins`, `Track2_Wins`, `Track3_Wins`, `Track4_Wins`, `TRACK5_Wins`) AS Series
FROM `Drivers` d INNER JOIN `Tracks` t
ON t.`FK` = d.`ID`
ORDER BY Series DESC;
This returns the user name associated with the FK. Also, try to use kebab_case and lower case for all your column and table name. Makes it much easier to run the code
I'm very inexperienced. I've prepared a select statement which gives the information I need to populate a matches table. However it is not suitable because it contains a where clause. Is there a different way to use it, or how can I change it so that it is suitable for INSERT INTO.
The tables are as follows:-
match_order
match_order_id||match_descrip||first_player||second_player
1 1v2 1 2
2 1v3 1 3
3 2v3 2 3
4 1v4 1 4
5 2v4 2 4
6 3v4 3 4
entries
entry_id||round_id||league_id||box_id||box_position
1 1 1 1 1
2 1 1 1 2
3 1 1 1 3
4 1 2 1 4
5 1 2 1 2
6 1 2 1 1
7 1 2 1 1
matches
match_id||round_id||league_id||box_id||match_order_id||player1||player2
I need to insert new rows every month for a new round of matches. League size, box size & positions change each month.
This is the statement which gives the correct rows.
SELECT e.round_id, e.league_id, e.box_id, mo.match_order_id, e.entry_id as player1, e1.entry_id as player2
FROM match_order mo
LEFT JOIN entries e ON mo.first_player = e.box_position
LEFT JOIN entries e1 ON mo.second_player = e1.box_position
WHERE e.round_id = e1.round_id AND e.league_id = e1.league_id AND e.box_id = e1.box_id
ORDER BY round_id, league_id, box_id, match_order_id
Any help & advise would be greatly appreciated.
Thank you
Assuming match_id is an auto-increment column, you have the data for the other columns. You can just add the INSERT statement before your SELECT.
INSERT INTO matches(round_id, leage_id, box_id, match_order_id, player1, player2)
SELECT e.round_id, e.league_id, e.box_id, mo.match_order_id, e.entry_id as player1, e1.entry_id as player2
FROM match_order mo
LEFT JOIN entries e ON mo.first_player = e.box_position
LEFT JOIN entries e1 ON mo.second_player = e1.box_position
WHERE e.round_id = e1.round_id AND e.league_id = e1.league_id AND e.box_id = e1.box_id
I am struggling at writing a query to get data from a table like this:
id food_id ingre_id
1 1 13
2 1 9
3 2 13
4 3 5
5 4 9
6 4 10
7 5 5
Assume in that table, each food only have 1 or 2 ingre ids. Then I want to have a table like this:
item_id ingre1_id ingre2_id
1 13 9
2 13 null //any food that have 1 ingre then set ingre2_id to null
3 5 null
4 9 10
5 5 null
Please suggest me a query to do such conversion. Thank you!
You can use aggregation. If you don't care about the ordering within a row:
select food_id, min(ingred_id) as ingred1_id,
(case when min(ingred_id) <> max(ingred_id) then max(ingred_id) end) as ingred2_id
from t
group by food_id;
Note: This use of min()/max() works specifically because you have two values. If you have more values, then ask another question with appropriate data.
This should produce what you asked for:
SELECT
a.`food_id` as `item_id`,
a.`ingre_id` as `ingre1_id`,
b.`ingre_id` as `ingre2_id`
FROM `food` a
LEFT JOIN `food` b
ON a.`id` <> b.`id` AND a.`food_id` = b.`food_id`
WHERE a.`id` < b.`id` OR b.`id` IS NULL
GROUP BY a.`food_id`
i have a problem concerning a select query in MYSQL
i have two different tables and i want to obtain a certain result
i used COUNT method which gave me only the results (>=1)
But in reality , i want to use all counts with zero included how to do it?
My query is:
SELECT
first.subscriber_id,
second.tag_id,
COUNT(*)
FROM
content_hits first
JOIN content_tag second ON first.content_id=second.content_id
GROUP BY
second.Tag_id,first.Subscriber_id<br>
First table:Content_hits
CONTENT_ID SUBSCRIBER_ID
30 1
10 10
34 4
32 2
40 3
28 3
30 6
31 8
12 3
Second table:Content_tag
CONTENT_ID TAG_ID
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 2
12 2
13 2
14 2
Result but incomplete For example:Subsrciber6 for tag_id=1 should have a count(*)=0
subscriber_id tag_id COUNT(*)
1 1 4
2 1 7
3 1 2
4 1 1
5 1 3
7 1 2
8 1 1
9 1 1
10 1 3
1 2 2
2 2 3
3 2 2
Now that you have further elaborated on what you actually want to achieve, it can be seen that the problem is much more complex. You actually want all combinations of subscriber_id and tag_id, and then count the number of actual entries in the joined table product. whew. So here goes the SQL:
SELECT combinations.tag_id,
combinations.subscriber_id,
-- correlated subquery to count the actual hits by tag/subscriber when joining
-- the two tables using content_id
(SELECT count(*)
FROM content_hits AS h
JOIN content_tag AS t ON h.content_id = t.content_id
WHERE h.subscriber_id = combinations.subscriber_id
AND t.tag_id = combinations.tag_id) as cnt
-- Create all combinations of tag/subscribers first, before counting anything
-- This will be necessary to have "zero-counts" for any combination of
-- tag/subscriber
FROM (
SELECT DISTINCT tag_id, subscriber_id
FROM content_tag
CROSS JOIN content_hits
) AS combinations
Not sure, but is this what you want?
SELECT first.subscriber_id, second.tag_id, COUNT(*) AS c
FROM content_hits first JOIN content_tag second ON first.content_id=second.content_id
GROUP BY second.Tag_id,first.Subscriber_id HAVING c = 0
I've tried a few of the similar SO questions, but I can't seem to figure it out.
On the first inner join, I only want to bring in DISTINCT function columns code and serial_id. So when I do my SUM selects, it calculates one per distinct. Ie there are multiple rows with the same func.code and func.serial_id. I only want 1 of them.
SELECT
sl.imp_id,
lat.version,
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN functions func ON sl.id = func.slot_id
INNER JOIN latest_status lat ON lat.code = func.code
AND lat.serial_id = func.serial_id
WHERE sl.id=55
GROUP BY sl.imp_id, lat.version
EDIT 2 - sample data explanation -------------------
slots - id, imp_id, name
functions - id, slot_id, code, serial_id
latest_status - id, code, serial_id, version, status
**slots**
id imp_id name
1 5 'the name'
2 5 'another name'
3 5 'name!'
4 5 'name!!'
5 5 'name!!!'
6 5 'testing'
7 5 'hi'
8 5 'test'
**functions**
id slot_id code serial_id
1 1 11HRK 10
2 2 22RMJ 11
3 3 26OLL 01
4 4 22RMJ 00
6 6 11HRK 10
7 7 11HRK 10
8 8 22RMJ 00
**latest_status**
id code serial_id version status
1 11HRK 10 1 F
1 11HRK 10 2 P
3 22RMJ 11 1 P
4 22RMJ 11 2 F
5 26OLL 01 1 F
6 26OLL 01 2 P
7 22RMJ 00 1 F
8 22RMJ 00 2 F
After running the query, the result should look like this:
imp_id version powered functional
5 1 1 3
5 2 2 2
The function table gets rolled up based on the code, serial_id. 1 row per code, serial_id.
It then gets joined onto the latest_status table based on the serial_id and code, which is a one (functions) to many (latest_status) relationship, so two rows come out of this, one for each version.
How about using DISTINCT?
SELECT
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN (Select DISTINCT id1, code, serial_id from functions) f On sl.rid = f.id1
INNER JOIN latest_status lat ON lat.code = f.code
AND lat.serial_id = f.serial_id
WHERE sl.id=55
GROUP BY sl.imp_id, lat.version
If you want only the distinct code and serial_id, you need to group by those not the imp_id and version. And end up with something like
SELECT
SUM(IF(lat.status = 'P',1,0)) AS powered,
SUM(IF(lat.status = 'F',1,0)) AS functional
FROM slots sl
INNER JOIN functions func ON sl.rid = func.id1
INNER JOIN latest_status lat ON lat.code = func.code
AND lat.serial_id = func.serial_id
WHERE sl.id=55
GROUP BY func.code, func.serial_id
However, this could all be rubish, without more data as tgo what some of those other columns are, but they dont seem to be the ones you wanted to group by.