Can i decide to have x null rows on a left join? - mysql

There is my issue :
I have two tables that i want to left join, and i want to display X rows depending on how many records there are in the second table.
Example :
TABLE_A TABLE_B
--------------------- -----------------------------------
| idA | yearA | | idB | idRefA | integ | lab |
|-------------------| |-------------------------------- |
| 1 | 2010 | | 20 | 2 | 54 | x |
| 2 | 2011 | | 20 | 2 | 50 | y |
| 3 | 2012 | | 20 | 2 | 28 | z |
| 4 | 2013 | | 21 | 3 | 18 | x |
| 5 | 2014 | | 21 | 3 | 22 | y |
--------------------- | 21 | 3 | 32 | z |
------------------------------------
There are my two tables.
This is my SQL query to join them :
SELECT * FROM TABLE_A
LEFT JOIN TABLE_B ON TABLE_A.ida = TABLE_B.idrefa
But i haven't the result that i expect, here is the result :
idA
yearA
idB
idRefA
integ
lab
1
2010
null
null
null
null
2
2011
20
2
28
z
2
2011
20
2
50
y
2
2011
20
2
54
x
3
2012
21
3
32
z
3
2012
21
3
22
y
3
2012
21
3
18
x
4
2013
null
null
null
null
5
2014
null
null
null
null
I am trying to have X rows on my LEFT JOIN (here X = 3). To complete the missing rows. Something like :
1 2010 19 1 0 x
1 2010 19 1 0 y
1 2010 19 1 0 z
...
Is it possible to do with a SELECT and LEFT JOIN ?
Here is my desired result :
ida
yearA
idb
idrefa
integ
lab
1
2010
null
null
null
null
1
2010
null
null
null
null
1
2010
null
null
null
null
2
2011
20
2
28
z
2
2011
20
2
50
y
2
2011
20
2
54
x
3
2012
21
3
32
z
3
2012
21
3
22
y
3
2012
21
3
18
x
Thanks for answer

Schemar and insert statements:
create table TABLE_A(idA int, yearA int);
insert into TABLE_A values( 1 , 2010 );
insert into TABLE_A values( 2 , 2011 );
insert into TABLE_A values( 3 , 2012 );
insert into TABLE_A values( 4 , 2013 );
insert into TABLE_A values( 5 , 2014 );
create table TABLE_B( idB int, idRefA int, integ int, lab varchar(10) );
insert into TABLE_B values( 20 , 2 , 54 , 'x' );
insert into TABLE_B values( 20 , 2 , 50 , 'y' );
insert into TABLE_B values( 20 , 2 , 28 , 'z' );
insert into TABLE_B values( 21 , 3 , 18 , 'x' );
insert into TABLE_B values( 21 , 3 , 22 , 'y' );
insert into TABLE_B values( 21 , 3 , 32 , 'z' );
Query#1 (for MySQL version older than 8.0):
SELECT min(ida)over() ida,min(yeara)over()yearA,idb,idrefa,integ,lab FROM TABLE_A
LEFT JOIN TABLE_B ON TABLE_A.ida = TABLE_B.idrefa
where TABLE_B.idrefa is null
union all
SELECT * FROM TABLE_A
LEFT JOIN TABLE_B ON TABLE_A.ida = TABLE_B.idrefa
where TABLE_B.idrefa is not null
Output:
ida
yearA
idb
idrefa
integ
lab
1
2010
null
null
null
null
1
2010
null
null
null
null
1
2010
null
null
null
null
2
2011
20
2
54
x
2
2011
20
2
50
y
2
2011
20
2
28
z
3
2012
21
3
18
x
3
2012
21
3
22
y
3
2012
21
3
32
z
Query#2 (for MySQL version 8.0 and above):
SELECT (case when idrefa is null then min(ida)over(partition by idrefa) else ida end)ida,(case when idrefa is null then min(yeara)over(partition by idrefa) else yearA end)yearA,idb,idrefa,integ,lab FROM TABLE_A
LEFT JOIN TABLE_B ON TABLE_A.ida = TABLE_B.idrefa
order by yearA
Output:
ida
yearA
idb
idrefa
integ
lab
1
2010
null
null
null
null
1
2010
null
null
null
null
1
2010
null
null
null
null
2
2011
20
2
28
z
2
2011
20
2
50
y
2
2011
20
2
54
x
3
2012
21
3
32
z
3
2012
21
3
22
y
3
2012
21
3
18
x
db<fiddle here

Related

Finding the latest record in each window - MariaDB/MySQL

In MariaDb 10.3, how to find the latest(based on timestamp) row for each window(or partition, I am not entirely clear on the terminology here)?
Consider the following table with data
ItemID
Itemname
Value
Timestamp
1
A
22
2021-12-22 20:01:00
1
A
2
2021-12-22 15:09:44
1
A
3
2021-12-22 14:39:49
2
B
54
2021-12-22 12:46:37
2
B
23
2021-12-22 12:17:52
2
B
43
2021-12-22 11:19:11
1
A
23
2021-12-22 04:00:58
1
A
53
2021-12-22 03:00:58
3
C
21
2021-12-21 04:00:58
2
B
74
2021-12-21 04:06:58
2
B
36
2021-12-21 04:06:09
1
A
34
2021-12-21 03:08:09
Desired output
ItemID
ItemName
Value
Timestamp
1
A
22
2021-12-22 20:01:00
2
B
54
2021-12-22 12:46:37
1
A
23
2021-12-22 04:00:58
3
C
21
2021-12-21 04:00:58
2
B
74
2021-12-21 04:06:58
1
A
34
2021-12-21 03:08:09
Following query generates expected result
WITH ordered AS (
SELECT
*,
LAG(`ItemID`) OVER (ORDER BY `Timestamp` DESC) AS LastItem
FROM dataset
)
SELECT `ItemID`, `ItemName`, `Value`, `Timestamp`
FROM ordered
WHERE `ItemID` <> `LastItem` OR `LastItem` IS NULL
ORDER BY `Timestamp` DESC
demo

Max(Date) query with another condition

my record:
SF_ID CardID Status Received_Date Meetup_Date
12 1 Yes 2015-01-12 2015-12-03
13 1 No 2015-12-01 NULL
14 1 No 2015-12-01 NULL
15 2 No 2015-12-02 NULL
16 2 No 2015-12-02 NULL
17 3 No 2015-12-01 NULL
18 4 No 2015-12-06 NULL
19 5 Yes 2015-11-30 2015-12-01
20 5 No 2015-11-30 NULL
22 5 No 2015-11-30 NULL
23 7 yes 2015-12-06 2015-12-07
Requirement #1:
all cardID where Received_Date is Minimum and Status
is No and Top 01 SF_ID. I've tried it in the following way without success:
SELECT CardSFID,
CardID,
CardSFShortDate
FROM CC_Shortfall AS [data]
WHERE ( CardSFShortDate = (SELECT TOP 1 PERCENT CardSFShortDate
FROM CC_Shortfall
WHERE CardID = [data].CardID) )
AND CardSFYesNo = 'No'
Requirement #2:
all cardID Where MeetUp_Date is Maximum and Status
is Yes and there are not any No Status under CardID
i've tried to do it in the following way without succcess:
SELECT CardSFID,
CardID,
CardSfShortRcvDate
FROM CC_Shortfall AS [data]
WHERE ( CardSfShortRcvDate = (SELECT Max(CardSfShortRcvDate)
FROM CC_Shortfall
WHERE CardID = [data].CardID) )
AND CardSFYesNo = 'Yes'

Select MYSQL records where child record in a set is missing

Here's the situation: If someone takes one course, they have to take a set of other courses as a supplement. How can I identify those courses a student has not yet taken?
Here are my tables:
tbl_course_dependency_lookup
courseid dependentid
133 57
133 55
133 71
167 57
167 99
tbl_user_course_completed
userid courseid
12 133
12 55
13 71
14 133
15 100
Here is the data that should be returned:
userid courseid dependentid
12 133 57
12 133 71
14 133 55
14 133 57
14 133 71
DROP TABLE IF EXISTS course_dependency;
CREATE TABLE course_dependency
(course_id INT NOT NULL
,dependent_id INT NOT NULL
,PRIMARY KEY(course_id,dependent_id)
);
INSERT INTO course_dependency VALUES
(133 ,57),
(133 ,55),
(133 ,71),
(167 ,57),
(167 ,99);
DROP TABLE IF EXISTS user_course;
CREATE TABLE user_course
(user_id INT NOT NULL
,course_id INT NOT NULL
,PRIMARY KEY(user_id,course_id)
);
INSERT INTO user_course VALUES
(12 ,133),
(12 ,55),
(13 ,71),
(14 ,133),
(15 ,100);
SELECT uc.*
, cd.dependent_id
FROM user_course uc
JOIN course_dependency cd
ON cd.course_id = uc.course_id
LEFT
JOIN user_course ucx
ON ucx.user_id = uc.user_id
AND ucx.course_id = cd.dependent_id
WHERE ucx.user_id IS NULL;
+---------+-----------+--------------+
| user_id | course_id | dependent_id |
+---------+-----------+--------------+
| 12 | 133 | 57 |
| 12 | 133 | 71 |
| 14 | 133 | 55 |
| 14 | 133 | 57 |
| 14 | 133 | 71 |
+---------+-----------+--------------+

Still show the proper set of time even if there's no entry for that time

I have this query where it gets the average and group the values by 15 mins from 12 AM to 11:45 PM.
SELECT FROM_UNIXTIME(t_stamp/1000, '%m/%d/%Y %l:%i %p') as t_stamp,
ROUND(AVG(CASE WHEN id = '001' THEN value END),2) Value1,
ROUND(AVG(CASE WHEN id = '002' THEN value END),2) Value2,
ROUND(AVG(CASE WHEN id = '003' THEN value END),2) Value3
FROM table1
WHERE tagid IN ("001", "002", "003") and
date(from_unixtime(t_stamp/1000)) BETWEEN "2014-05-01" AND "2014-05-01"
GROUP BY DATE(from_unixtime(t_stamp/1000)), HOUR(from_unixtime(t_stamp/1000)), MINUTE(from_unixtime(t_stamp/1000)) DIV 15
The output looks like this
t_stamp | Value1 | Value2 | Value3
05/01/2014 12:00 AM | 199 | 99 | 100
05/01/2014 12:15 AM | 299 | 19 | 140
05/01/2014 12:30 AM | 399 | 59 | 106
05/01/2014 12:45 AM | 499 | 59 | 112
.
.
.
05/01/2014 11:00 PM | 149 | 199 | 100
05/01/2014 11:15 PM | 599 | 93 | 123
05/01/2014 11:30 PM | 129 | 56 | 150
05/01/2014 11:45 PM | 109 | 60 | 134
It works fine but I've noticed that sometimes if there's no entry for like the time 12:30 instead of showing
t_stamp | Value1 | Value2 | Value3
05/01/2014 12:00 AM | 199 | 99 | 100
05/01/2014 12:15 AM | 299 | 19 | 140
05/01/2014 12:30 AM | Null | Null | Null
05/01/2014 12:45 AM | 499 | 59 | 112
It will show the set of time like this:
t_stamp | Value1 | Value2 | Value3
05/01/2014 12:00 AM | 199 | 99 | 100
05/01/2014 12:15 AM | 299 | 19 | 140
05/01/2014 12:33 AM | 122 | 141 | 234
05/01/2014 12:45 AM | 499 | 59 | 112
What I would like to happen is when there's no time for that 15 min group it will still show the proper set of time and then just show null on the column values. The output I would like is like this:
t_stamp | Value1 | Value2 | Value3
05/01/2014 12:00 AM | 199 | 99 | 100
05/01/2014 12:15 AM | 299 | 19 | 140
05/01/2014 12:30 AM | Null | Null | Null
05/01/2014 12:45 AM | 499 | 59 | 112
How can I do this?
Thank You.
You need a table that's a source of cardinal numbers as a start for this. For the moment let's assume it exists, and it's called cardinal.
Then, you need to create a query (a virtual table) that will return rows with timestamps every fifteen minutes, starting with the earliest relevant timestamp and ending with the latest. Here's how to do that for your query.
SELECT '2014-05-01' + INTERVAL (cardinal.n * 15) MINUTE as t_stamp
FROM cardinal
WHERE cardinal.n <= 24*4
Then you need to JOIN that virtual table to your existing query, as follows
SELECT DATE_FORMAT(t_stamp.t_stamp, '%m/%d/%Y %l:%i %p') t_stamp,
ROUND(AVG(CASE WHEN id = '001' THEN value END),2) Value1,
ROUND(AVG(CASE WHEN id = '002' THEN value END),2) Value2,
ROUND(AVG(CASE WHEN id = '003' THEN value END),2) Value3
FROM table1 AS t
LEFT JOIN (
SELECT '2014-05-01' + INTERVAL (cardinal.n * 15) MINUTE as t_stamp
FROM cardinal
WHERE cardinal.n <= 24*4
) AS t_stamp
ON t_stamp.t_stamp = FROM_UNIXTIME(t.t_stamp/1000)
WHERE tagid IN ("001", "002", "003")
AND date(from_unixtime(t_stamp/1000)) BETWEEN "2014-05-01" AND "2014-05-01"
GROUP BY DATE(from_unixtime(t_stamp/1000)),
HOUR(from_unixtime(t_stamp/1000)),
MINUTE(from_unixtime(t_stamp/1000)) DIV 15
Notice that the LEFT JOIN makes sure the rows will NULL values from your original query get included in the result set.
Now, where does this magical cardinal table come from?
You can generate it as two views, like this. This particular view generates numbers from 0 to 100 000, which is more than enough for quarters of hours for a year.
CREATE OR REPLACE VIEW cardinal10 AS
SELECT 0 AS N UNION
SELECT 1 AS N UNION
SELECT 2 AS N UNION
SELECT 3 AS N UNION
SELECT 4 AS N UNION
SELECT 5 AS N UNION
SELECT 6 AS N UNION
SELECT 7 AS N UNION
SELECT 8 AS N UNION
SELECT 9 AS N;
CREATE OR REPLACE VIEW cardinal AS
SELECT A.N + 10*(B.N + 10*(C.N + 10*(D.N + 10*(E.N)))) AS N
FROM cardinal10 A,cardinal10 B,cardinal10 C,
cardinal10 D,cardinal10 E;
Here's a writeup on the topic.
http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/

Searching a Record from Middle of the Table

I am facing issue in finding the data from MySql table.
Table A:
+-------+-------------+------+-----+-------------------+-------+
| ID | Table_b_fk |Value | age | name | score |
+-------+-------------+------+-----+-------------------+-------+
| 01 | 01 | 255 | 21 | Tom | 65 |
| 02 | 02 | 36 | 20 | Peter | 95 |
| 03 | 03 | 25 | 22 | John | 65 |
| 04 | 04 | 36 | 20 | Bond | 95 |<<----First
| 05 | 05 | 258 | 22 | Smith | 65 |
| 06 | 06 | 420 | 20 | Robert | 95 |
| 07 | 07 | 258 | 22 | Nisarg Patel | 65 |
| 08 | 08 | 16 | 21 | Peter | 95 |
| 09 | 09 | 25 | 23 | J0k | 65 |
| 10 | 10 | 36 | 22 | Prodigitalson | 95 |
| 11 | 11 | 205 | 22 | Silver | 65 |<<----Next
| 12 | 12 | 37 | 20 | Json | 95 |
| 13 | 13 | 285 | 23 | Villa | 65 |
| 14 | 14 | 36 | 22 | Parker | 95 |
+-------+-------------+------+-----+-------------------+-------+
Table B:
+-------+-------------+------+-----+-------------------+-------+
| ID | Result | M1 | M2 | name | score |
+-------+-------------+------+-----+-------------------+-------+
| 01 | Pass | 30 | 26 | Tom | 65 |
| 02 | Pass | 30 | 20 | Peter | 95 |
| 03 | Pass | 25 | 60 | John | 65 |
| 04 | Pass | 100 | 100 | Bond | 95 |<<----First
| 05 | Pass | 55 | 65 | Smith | 65 |
| 06 | Pass | 80 | 95 | Robert | 95 |
| 07 | Pass | 65 | 75 | Nisarg Patel | 65 |
| 08 | Pass | 56 | 71 | Peter | 95 |
| 09 | Pass | 90 | 96 | J0k | 65 |
| 10 | Pass | 96 | 96 | Prodigitalson | 95 |
| 11 | Pass | 100 | 100 | Silver | 65 |<<----Next
| 12 | Pass | 47 | 92 | Json | 95 |
| 13 | Pass | 82 | 73 | Villa | 65 |
| 14 | Pass | 86 | 72 | Parker | 95 |
+-------+-------------+------+-----+-------------------+-------+
I am joining TableA & TableB, where in TableA Table_b_fk is foreign key to TableB.
I am finding the record which matches the TableB column M1 & M2 = 100.
My Scenario: 1
I know the first occurrence of the match record ID : 04 in TableA. I want to do a search to find the next record with M1 & M2 = 100. (Record Id-11) But the search should not start from 01. It should start from the last found record Id. That is from O4 the search should start to find the next occurrence of the record.
My Try:
I tried to find using Limit but it didn't help me to find. Can some one help me in this?
Edit: 1
My Scenario: 2
In my second case my TableB has repeated Data and the ID was foreign in TableA. How can I fins the record. ? with the matching ID/M1/M2 values: I found a solution for that. I just want to find the Current Record FOREIGN KEY and Check for the next occurrence of the record in the same table and I can get the next record rite?
In this case my TableB record are not as same as TableA records. In other words my TableA records will point to tableA. Many-to-one. Is this rite?
Edit: 2
Thanks for all your efforts and knowledge I found a solution for scenario:2 check it:
CREATE TABLE TableB (
ID Int,
Result VARCHAR(20),
M1 INT,
M2 INT,
name VARCHAR(20),
Score INT);
INSERT INTO TableB VALUES
( 11 , 'Pass' , 30 , 26 , 'Tom' , 65 ),
( 13 , 'Pass' , 30 , 20 , 'Peter' , 95 ),
( 80 , 'Pass' , 25 , 60 , 'John' , 65 ),
( 81 , 'Pass' , 100 , 100 , 'Bond' , 95 ),
( 90 , 'Pass' , 55 , 65 , 'Smith' , 65 ),
( 96 , 'Pass' , 80 , 95 , 'Robert' , 95 ),
( 97 , 'Pass' , 65 , 75 , 'Nisarg Patel' , 65 ),
( 98 , 'Pass' , 56 , 71 , 'Peter' , 95 ),
( 99 , 'Pass' , 90 , 96 , 'J0k' , 65 ),
( 100 , 'Pass' , 96 , 96 , 'Prodigitalson' , 95 ),
( 101 , 'Pass' , 10 , 10 , 'Silver' , 65 ),
( 103 , 'Pass' , 47 , 92 , 'Json' , 95 ),
( 201 , 'Pass' , 82 , 73 , 'Villa' , 65 ),
( 222 , 'Pass' , 86 , 72 , 'Parker' , 95 )
;
CREATE TABLE TableA
(`ID` int, `Table_b_fk` int, `Value` int, `age` int, `name` varchar(13), `score` int)
;
INSERT INTO TableA
(`ID`, `Table_b_fk`, `Value`, `age`, `name`, `score`)
VALUES
(01, 11, 255, 21, 'Tom', 65),
(02, 81, 36, 20, 'Peter', 95),
(03, 80, 25, 22, 'John', 65),
(04, 97, 36, 20, 'Bond', 95),
(05, 81, 258, 22, 'Smith', 65),
(06, 06, 420, 20, 'Robert', 95),
(07, 81, 258, 22, 'Nisarg Patel', 65),
(08, 08, 16, 21, 'Peter', 95),
(09, 96, 25, 23, 'J0k', 65),
(10, 101, 36, 22, 'Prodigitalson', 95),
(11, 222, 205, 22, 'Silver', 65),
(12, 12, 37, 20, 'Json', 95),
(13, 201, 285, 23, 'Villa', 65),
(14, 101, 36, 22, 'Parker', 95)
;
Solution for that is:
SELECT a.id
FROM TableB b
INNER JOIN TableA a
ON a.Table_b_fk = b.id
WHERE M1 = 100 and M2 = 100 AND a.ID>4 limit 1
where the limit just limits the next record.. (answer is 5).
I case of Doctrine 2: Use the below Query code.
$qry = $this->manager()->createQueryBuilder()
->select(array('e', 's'))
->from('YOUR_DOMAIN', 'e')
->Join('e.table_b_k', 's')
->where("s.m1 = ?", $valueone)
->andwhere("s.m2 = ?", $valuetwo)
->andwhere("e.id > ?", $currentrecord)
->setMaxResult(1);
Note: YOUR_DOMAIN here is the TableA. TableA and TableB should be joined through the Mapping so we dont need to Join/Reference int he Query.. directly as TableB. The will be done by the second line Join in the above example. It is not tested as of now.
What about this give it a try
SELECT b.id AS next_id FROM tableb b LEFT JOIN tablea a
ON (b.id =a.Table_b_fk ) WHERE b.M1=100 AND b.M2 =100 AND b.id >4
ORDER BY b.id ASC LIMIT 1
It gives the next occurrence of *M1 =100 and M2 =100 *
See Fiddle Example it returns 11 the next occurrence *M1 =100 and M2 =100 *
If I understand your question correctly, I think you are looking for this:
SET #id:=4;
SELECT *
FROM TableA
WHERE Table_b_fk =
(SELECT MIN(ID)
FROM TableB
WHERE (M1,M2) = (SELECT M1, M2 FROM TableB WHERE ID=#id)
AND ID>#id)
This query will select the second row from TableA that has M1=100 and M2=100 in the second table.
try this
SELECT a.id
FROM TableB b
INNER JOIN TableA a
ON a.Table_b_fk = b.id
WHERE M1 = 100 and M2 = 100 AND b.ID>4
output:
ID
11
demo FIDLLE
I am finding the record which matches the TableB column M1 & M2 = 100.
Assuming you mean:
I am finding the tableA record which matches the TableB column M1 = 100 AND M2 = 100.
SELECT *
FROM table_a a
WHERE EXISTS (
SELECT *
FROM table_b b
WHERE b.id = a.tableb_fk
AND b.m1 = 100 AND b.m2 = 100
);
UPDATE: since the OP appears to want to suppress the first matching record from the result (I assume: the one with the lowest id), one could add an extra EXIST to the WHERE clause to suppress the first match:
SELECT *
FROM table_a a
WHERE EXISTS (
SELECT *
FROM table_b b
WHERE b.id = a.tableb_fk
AND b.m1 = 100 AND b.m2 = 100
AND EXISTS (
SELECT *
FROM table_b bb
WHERE bb.id < b.id
AND bb.m1 = 100 AND bb.m2 = 100
)
);