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!
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'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 a mysql table that holds data for team games.
Objective:
Count the number of times other SquadID's have have shared the same Team value as SquadID=21
// Selections table
+--------+---------+------+
| GameID | SquadID | Team |
+--------+---------+------+
| 1 | 5 | A |
| 1 | 7 | B |
| 1 | 11 | A |
| 1 | 21 | A |
| 2 | 5 | A |
| 2 | 7 | B |
| 2 | 11 | A |
| 2 | 21 | A |
| 3 | 5 | A |
| 3 | 7 | B |
| 3 | 11 | A |
| 3 | 21 | A |
| 4 | 5 | A |
| 4 | 11 | B |
| 4 | 21 | A |
| 5 | 5 | A |
| 5 | 11 | B |
| 5 | 21 | A |
| 6 | 5 | A |
| 6 | 11 | B |
| 6 | 21 | A |
+--------+---------+------+
// Desired Result
+---------+----------+
| SquadID | TeamMate |
+---------+----------+
| 5 | 6 |
| 7 | 0 |
| 11 | 3 |
| 21 | 6 |
+----------+---------+
I've attempted to use a subquery specifying the specific player I wish to compare with and because this subquery has multiple rows, I've used in instead of =.
// Current Query
SELECT
SquadID,
COUNT(Team IN (SELECT Team FROM selections WHERE SquadID=21) AND GameID IN (SELECT GameID FROM selections WHERE SquadID=21)) AS TeamMate
FROM
selections
GROUP BY
SquadID;
The result I'm getting is the number of Games a user has played rather than the number of games a user has been on the same team as SquadID=21
// Current Result
+---------+----------+
| SquadID | TeamMate |
+---------+----------+
| 5 | 6 |
| 7 | 3 |
| 11 | 6 |
| 21 | 6 |
+---------+----------+
What am I missing?
// DESCRIBE selections;
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| GameID | int(11) | NO | PRI | 0 | |
| SquadID | int(4) | NO | PRI | NULL | |
| Team | char(1) | NO | | NULL | |
| TeamID | int(11) | NO | | 1 | |
+---------+---------+------+-----+---------+-------+
General rule is to avoid nested selects and look for a better way of logically arranging joins. Lets look at a cross join:
From selections s1
inner join selects s2 on s1.gameid = s2.gameid and s1.team = s2.team
This will produce a cross joined list of each squadID that participated with another squadID (IE: they were in the same game and on same team). We are only interested in the times where the squad participated with squad 21, so add a where clause:
where s2.squadid = 21
Then it's simply choosing the field/count you want:
select s1.squad, count(1) as teammate
any aggregate needs a group by
group by s1.squad
Combine it together and give a go. Oddly, this will produce a list where squad 21 will be showing as playing on it's own team all 6 times. Adding a where clause can eliminate this
where s1.squadid <> s2.squadid
SELECT SquadID, count(t1.team) as TeamMate
FROM selections as t1 join
(select distinct team, gameid from selections where SquadID=21) as t2
on t1.Team=t2.Team and t1.Gameid=t2.Gameid
GROUP BY SquadID
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
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.