This is a continuation of my previous question.
Assume we have three tables. A main table and two id tables.
+-----+-----+--------------------------------------+
| cid | pid | date1 | date2 | date3 |
+-----+-----+--------------------------------------+
| 1 | 2 | NULL | 2014-03-24 | 2014-03-24 |
| 3 | 1 | 2014-06-13 | NULL | NULL |
| 4 | 3 | NULL | 2014-09-14 | NULL |
| 2 | 1 | NULL | NULL | 2014-08-15 |
| 4 | 3 | 2014-01-10 | NULL | NULL |
| 1 | 4 | 2014-02-15 | NULL | NULL |
| 4 | 2 | NULL | 2014-01-06 | 2014-01-12 |
+-----+-----+------------+------------+------------+
+----+----------+ +----+--------+
| id | city | | id | person |
+----+----------+ +----+--------+
| 1 | 'Dallas' | | 1 | 'John' |
| 2 | 'Berlin' | | 2 | 'Jack' |
| 3 | 'Topeka' | | 3 | 'Doug' |
| 4 | 'London' | | 4 | 'Pete' |
+----+----------+ +----+--------+
Ok, now i'd like to make a select to get one row per city in the result. The row has to contain the city, the max of each date (date1, date2, date3) of this city and the person that belongs to the max of the three max dates.
Result:
+--------+--------+--------------------------------------+
| city | person | date1 | date2 | date3 |
+--------+--------+--------------------------------------+
| Dallas | Jack | 2014-02-15 | 2014-03-24 | 2014-03-24 |
| Berlin | John | NULL | NULL | 2014-08-15 |
| Topeka | John | 2014-06-13 | NULL | NULL |
| London | Doug | 2014-01-10 | 2014-09-14 | 2014-01-12 |
+--------+--------+------------+------------+------------+
Mhh... I thought it would't be that difficult.
see the fiddle
I think this might work.
select c.city, p.person, y.date1, y.date2, y.date3
from (select x.cid, x.date1, x.date2, x.date3, greatest(ifnull(x.date1, '0000-01-01'), ifnull(x.date2, '0000-01-01'), ifnull(x.date3, '0000-01-01')) as maxdate
from (select cid, max(date1) as date1, max(date2) as date2, max(date3) as date3
from main
group by cid) as x)
as y
join main m
on m.cid = y.cid and
(m.date1 = y.maxdate or m.date2 = y.maxdate or m.date3 = y.maxdate)
join city c
on y.cid = c.id
join person p
on m.pid = p.id
It starts by creating 'x' which is a table with the max dates for each city. Then it creates 'y' where it adds on the highest of the 3 dates. Then it joins with the main table to find the row for the city with the highest date. And then it joins the city and person table to get the names rather than the ids.
Related
I have two tables.
support_table
+------+-------------+
| num | num_explain |
+------+-------------+
| 1 | 01 |
| 2 | 01 |
| 2 | 02 |
| 3 | 01 |
| 3 | 02 |
| 3 | 03 |
| 4 | 01 |
| 4 | 02 |
| 4 | 03 |
| 4 | 04 |
| 5 | 01 |
| 5 | 02 |
| 5 | 03 |
| 5 | 04 |
| 5 | 05 |
+------+-------------+
class_room
+-----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| seq_no | varchar(20) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| subjects | varchar(20) | YES | | NULL | |
| no_of_student | varchar(20) | YES | | NULL | |
| student_roll_no | varchar(20) | YES | | NULL | |
+-----------------+-------------+------+-----+---------+-------+
Now I've tried the below query to insert data into table class_room:
INSERT INTO class_room (seq_no,name,subjects,no_of_student,student_roll_no)
SELECT '1', 'class11', 'physics', num, num_explain FROM support_table
WHERE num='3';
this query works totally fine for me and it creates 3 rows. Now the table looks like below:
+---------+---------+----------+---------------+-----------------+
| seq_no | name | subjects | no_of_student | student_roll_no |
+---------+---------+----------+---------------+-----------------+
| 1 | class11 | physics | 3 | 01 |
| 1 | class11 | physics | 3 | 02 |
| 1 | class11 | physics | 3 | 03 |
+---------+---------+----------+---------------+-----------------+
Now I want to update this table, so I've tried the below code:
UPDATE class_room
SET name='class11', subjects='chemistry', no_of_student =
(SELECT num_explain FROM support_table WHERE num='4')
WHERE seq_no='1';
But this query IS showing that
Subquery returns more than one row.
Here I want that in class_room table no_of_student will be changed to '4' and student_roll_no will be upto '04' and instead of 3 rows, 4 rows will be created.
You have 3 rows in the table but you expect finally to get 4 rows.
This can't be done with an UPDATE statement which does not add new rows.
The simplest way to do what you want is to delete the current rows and then insert:
delete from class_room where no_of_student = 3;
insert into class_room (seq_no,name,subjects,no_of_student,student_roll_no)
select '1', 'class11','chemistry',num,num_explain
from support_table
where num='4';
See the demo.
| seq_no | name | subjects | no_of_student | student_roll_no |
| ------ | ------- | --------- | ------------- | --------------- |
| 1 | class11 | chemistry | 4 | 1 |
| 1 | class11 | chemistry | 4 | 2 |
| 1 | class11 | chemistry | 4 | 3 |
| 1 | class11 | chemistry | 4 | 4 |
= Can be used when the subquery returns only 1 value.
When subquery returns more than 1 value, you will have to use IN :
UPDATE class_room set name='class11',subjects='chemistry',no_of_student IN (select num_explain FROM support_table WHERE num='4')LIMIT 1 WHERE seq_no='1';
Example :
select *
from table
where id IN (multiple row query);
Another example :
SELECT *
FROM Students
WHERE Marks = (SELECT MAX(Marks) FROM Students) --A Example Subquery returning 1 value
SELECT *
FROM Students
WHERE Marks IN
(SELECT Marks
FROM Students
ORDER BY Marks DESC
LIMIT 10) --Example Subquery returning 10 values
A good explanation can be found here by #Raging bull
I have a database table which has a person's id, name, and time (in milliseconds, stored as an int). For example:
| id | name | totalTime |
| --- | ------ | --------- |
| 1 | Bob | 16280 |
| 2 | Andy | 17210 |
| 3 | Bill | 15320 |
| 4 | Matt | 14440 |
| 5 | Steven | 17570 |
| 6 | Tom | NULL |
| 7 | Angus | 17210 |
| 8 | Will | NULL |
| 9 | Jack | 17410 |
| 10 | Alex | 16830 |
Not necessarily all people have a time (thus the nulls).
I would like to have another two columns - one which shows the rank/position of each person, and another which shows the difference in time (milliseconds) between the best (i.e. minimum) time and each row's time.
I have managed to write a MySQL 8.x query which does the ranks:
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL THEN RANK() OVER ( PARTITION BY (CASE WHEN totalTime IS NOT NULL THEN 1 ELSE 0 END) ORDER BY totalTime ) END) totalRank
FROM results
ORDER BY -totalRank DESC;
...and outputs this:
| id | name | totalTime | totalRank |
| --- | ------ | --------- | --------- |
| 4 | Matt | 14440 | 1 |
| 3 | Bill | 15320 | 2 |
| 1 | Bob | 16280 | 3 |
| 10 | Alex | 16830 | 4 |
| 2 | Andy | 17210 | 5 |
| 7 | Angus | 17210 | 5 |
| 9 | Jack | 17410 | 7 |
| 5 | Steven | 17570 | 8 |
| 6 | Tom | NULL | NULL |
| 8 | Will | NULL | NULL |
...but have not been able to figure out the SQL to add another column with the time difference.
Below is an example of what I would like, but can't figure out how to do:
| id | name | totalTime | totalRank | difference |
| --- | ------ | --------- | --------- | ---------- |
| 4 | Matt | 14440 | 1 | 0 |
| 3 | Bill | 15320 | 2 | 880 |
| 1 | Bob | 16280 | 3 | 1840 |
| 10 | Alex | 16830 | 4 | 2390 |
| 2 | Andy | 17210 | 5 | 2770 |
| 7 | Angus | 17210 | 5 | 2770 |
| 9 | Jack | 17410 | 7 | 2970 |
| 5 | Steven | 17570 | 8 | 3130 |
| 6 | Tom | NULL | NULL | NULL |
| 8 | Will | NULL | NULL | NULL |
I have this available as a DB Fiddle: https://www.db-fiddle.com/f/gQvSeij2EKSufYp9VjbDav/0
Thanks in advance for any help!
You can use a CTE to get the min totalTime and use it to calculate the difference:
WITH cte as (SELECT MIN(totalTime) minTotalTime FROM results)
SELECT id, name, totalTime,
CASE WHEN totalTime IS NOT NULL
THEN RANK() OVER (PARTITION BY (
CASE
WHEN totalTime IS NOT NULL THEN 1
ELSE 0
END
) ORDER BY totalTime)
END totalRank,
totalTime - (SELECT minTotalTime from cte) difference
FROM results
ORDER BY -totalRank DESC;
See the demo.
Results:
| id | name | totalTime | totalRank | difference |
| --- | ------ | --------- | --------- | ---------- |
| 4 | Matt | 14440 | 1 | 0 |
| 3 | Bill | 15320 | 2 | 880 |
| 1 | Bob | 16280 | 3 | 1840 |
| 10 | Alex | 16830 | 4 | 2390 |
| 2 | Andy | 17210 | 5 | 2770 |
| 7 | Angus | 17210 | 5 | 2770 |
| 9 | Jack | 17410 | 7 | 2970 |
| 5 | Steven | 17570 | 8 | 3130 |
| 6 | Tom | | | |
| 8 | Will | | | |
Add min() window function
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL THEN RANK() OVER ( PARTITION BY (CASE WHEN totalTime IS NOT NULL THEN 1 ELSE 0 END) ORDER BY totalTime ) END) totalRank
,totaltime - min(totaltime) over() diff
FROM results
ORDER BY -totalRank DESC;
SELECT subtable.id,
subtable.NAME,
subtable.totalTime,
subtable.diff,
IIF(subtable.totalTime IS NULL,NULL,subtable.rowno) as bisi
FROM (
select *,
ROW_NUMBER() OVER (ORDER BY totalTime desc) as rowno,
totalTime -
(
select min(rst.totalTime)
from results rst) as diff
from results) subtable;
I would do this way in MS-SQL or alternatively in MYSQL
SELECT subtable.id,
subtable.NAME,
subtable.totalTime,
subtable.diff,
IF (subtable.totalTime IS NULL, NULL, subtable.rowno) as bisi
FROM (
select *,
ROW_NUMBER() OVER (ORDER BY totalTime desc) as rowno,
totalTime -
(
select min(rst.totalTime)
from results rst) as diff
from results) subtable;
Serg's answer is correct. I would write it as:
SELECT id, name, totalTime,
(CASE WHEN totalTime IS NOT NULL
THEN RANK() OVER (PARTITION BY (totalTime IS NULL) ORDER BY totalTime)
END) as totalRank,
totaltime - MIN(totaltime) OVER() as diff
FROM results
ORDER BY (totalTime IS NOT NULL) DESC, totalRank;
The differences are:
Simplifying the PARTITION BY. You use CASE, but MySQL conveniently treats booleans as "real" values.
Expressing the ORDER BY in a more intuitive fashion.
I'm working on a query where I need to count distinct CarId row when the column LocationId is not null and get all CarId if its null or 0 but the query that I tried distincts all the CarId even if its null
#LocId int
Select Count(distinct a.CarId) from VehicleDetails a
inner join VehicleDocuments b on a.DocId=b.DocId
left join VehicleShipmentDetails dpg on dpg.VehicleShipmentId= b.VehicleShipmentId
where b.LogicalDelete=0 and a.LogicalDelete=0
and (dpg.LocationId= #LocId or dpg.LocationId= 0 or dpg.LocationId is null)
| ID | CarId | LocationId | DateCreated |
|------+----------------+-----------------+---------------|
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 12/30/2018 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
| 7 | 2 | 5 | 03/13/2019 |
Desired output:
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 03/13/2019 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
Current Output
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | 5 | 01/14/2019 |
| 3 | 4 | 3 | 01/10/2019 |
| 4 | 3 | 5 | 02/14/2019 |
Im getting a count of 4 but i needed to have 6 as the Count
EDIT: My goal is to remove the row to Distinct CarId if the value of the LocationId is Null or 0 but on my Current code, It distincts all CarId that is null,0 and equals to #LocId
You can query something like this, replace your_table by your actual set of data.
SELECT ID, CardId, LocationId, DateCreated
FROM your_table as T
WHERE NOT EXISTS (SELECT *
FROM your_table as T1
WHERE T.ID > T1.ID AND T.CarID = T1.CarID)
In SQL, you can use the statement CASE to manage conditions (just like the "if then else" in other programming languages). In your case this function could help because you have two differents cases to handle.
I have been working with SQL joins and kinda stuck with following scenario:
Table 1: PK(ID, GRADE)
| ID | Grade | Student_Count |
| 1 | 10th | 20 |
| 1 | 9th | 20 || 2 | 10th | 20 || 2 | 9th | 20 |
Table 2:PK(ID, Grade, Visited_Date)
| ID | Grade | Visited | Visit_Date |
| 1 | 10th | Yes | 25-Dec-2015 |
| 1 | 10th | No | 26-Dec-2015 |
| 1 | 9th | Yes | 28-Dec-2015 |
| 1 | 9th | No | 29-Dec-2015 |
| 2 | 10th | Yes | 27-Dec-2015 |
| 2 | 9th | No | 30-Dec-2015 |
What i need is a SELECT query which returns data from both the tables for a given ID in such a way that output rows should match the data of the Table 2 (no all possible combinations like cross/dot product) along with non-common columns from Table 1.
For example for ID "1" the output should be:
| ID | Grade | Student_Count | Visited | Visit_date |
| 1 | 10th | 20 | Yes | 25-Dec-2015 |
| 1 | 10th | 20 | No | 26-Dec-2015 |
| 1 | 9th | 20 | Yes | 28-Dec-2015 |
| 1 | 9th | 20 | No | 29-Dec-2015 |
Note: There is no foreign key association between both the tables.
You have to JOIN both tables on the id and grade fields.
SELECT b.ID, b.Grade, a.Student_Count, b.Visited, b.Visit_date
FROM table2 b
INNER JOIN table1 a
ON a.ID = b.ID AND a.Grade = b.Grade
ORDER BY a.ID
I have a table keyed with date/person which has two value columns (val1, val2). In most cases they are both filled. However, there are some cases (which need fixing) where one of them is filled, and the other is null. These cases typically occur in pairs, one day apart. For each person, no two pairs will be within a month of each other.
I have selected all dates which fall within 3 days of another entry (to account for weekends) for a given person using the following query:
SELECT distinct t1.* from mytable t1
INNER JOIN mytable t2 ON t1.person = t2.person and t1.date <> t2.date
WHERE abs(datediff(t1.date,t2.date))<= 3
This returns:
+------------+------------+-------+-------+
| date | person | val1 | val2 |
+------------+------------+-------+-------+
| 2009-10-26 | A | null | 62 |
| 2009-10-27 | A | 4 | null |
| 2010-01-02 | A | 2 | null |
| 2010-01-04 | A | null | 101 |
| 2010-01-04 | B | null | -4 |
| 2010-01-06 | B | 3 | null |
+------------+------------+-------+-------+
Now what I'd like to do (and this is where I'm stuck), is to update the null value for the earlier date of each pair using the missing value taken from the other, to create something like this:
+------------+------------+-------+-------+
| date | person | val1 | val2 |
+------------+------------+-------+-------+
| 2009-10-26 | A | *4 | 62 |
| 2009-10-27 | A | 4 | null |
| 2010-01-02 | A | 2 | *101 |
| 2010-01-04 | A | null | 101 |
| 2010-01-04 | B | *3 | -4 |
| 2010-01-06 | B | 3 | null |
+------------+------------+-------+-------+
Thanks in advance!