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 |
+---------+-----------+--------------+
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/
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
)
);