Searching a Record from Middle of the Table - mysql
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
)
);
Related
Can i decide to have x null rows on a left join?
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
Get difference between two records
I got a User-Information table where every 24 hours a new record is added for each user. This record contains a user_id, a value (a counter) and the creation date. TBL_EXAMPLE ID | user_id | cnt_val | record_date -------------------------------------------- 1 | 10 | 46 | 2019-02-05 12:14:35 2 | 21 | 12 | 2019-02-05 12:14:35 3 | 32 | 453 | 2019-02-05 12:14:35 4 | 10 | 23 | 2019-02-06 16:11:21 5 | 21 | 34 | 2019-02-06 16:11:21 6 | 32 | 480 | 2019-02-06 16:11:21 7 | 10 | 31 | 2019-02-07 11:34:25 8 | 21 | 44 | 2019-02-07 11:34:25 9 | 32 | 489 | 2019-02-07 11:34:25 ... Expected Result: User 10 Counter: 46 .. 31 --> Difference: 15 User 21 Counter: 12 .. 44 --> Difference: 32 User 32 Counter: 453.. 489 --> Difference: 36 I want to make a list of each difference for each specific user from the oldest to the newest data record in the table dynamically.
you could use inner join twice on table_exeple and a subquery for min and max date select distinct t1.user_id, t1.cnt_va - t2.cnt_val from ( select user_id , min(date) min_date, max(date) max_date from TTBL_EXAMPLE group by user_id ) tmm inner join TTBL_EXAMPLE t2 ON t2.date = tmm.max_date and t2.user_id = tmm.user_id inner join TBL_EXAMPLE t1 ON t1.date = tmm.min_date and t1.user_id = tmm.user_id
How can I club values in MySql
I have two columns coming from my sql query- month, value i.e. values are coming monthwise. My requirement is to club these months in the group of 3 months wise...and the values should come the average of these 3. Ex.I have following data- Month Values Mar-14 50 Apr-14 51 May-14 52 Jun-14 53 Jul-14 54 Aug-14 55 Sep-14 56 Oct-14 57 Nov-14 58 Dec-14 59 Jan-15 60 Feb-15 61 Mar-15 62 Apr-15 63 May-15 64 Jun-15 65 Jul-15 66 Aug-15 67 Sep-15 68 Oct-15 69 Nov-15 70 Dec-15 71 Jan-16 72 Feb-16 73 Mar-16 74 Apr-16 75 May-16 76 Jun-16 77 Jul-16 78 Aug-16 79 Sep-16 80 Oct-16 81 Nov-16 82 Dec-16 83 Jan-17 84 Feb-17 85 Mar-17 86 How can I achieve following output in MySql- 3 Months Clubing Avg of Values Mar-14 51 Jun-14 54 Sep-14 57 Dec-14 60 Mar-15 63 Jun-15 66 Sep-15 69 Dec-15 72 Mar-16 75 Jun-16 78 Sep-16 81 Thanks in Advance
A bit messy but you could use variables -assuming you have an incrementing id column (or soemthing you can order by) drop table if exists t; create table t(id int auto_increment primary key,Month varchar(10), Valus int); insert into t (month,valus) values ('Mar-14', 50), ('Apr-14', 51), ('May-14', 52), ('Jun-14', 53), ('Jul-14', 54), ('Aug-14', 55), ('Sep-14', 56), ('Oct-14', 57), ('Nov-14', 58), ('Dec-14', 59); select id,mth,rt from ( select id,month,valus, #count:=#count+1 counter, if(#count=1,#mth:=month,#mth:=#mth) mth, if(#count=1,#block:=#block+1,#block:=#block) block, if(#count<3,#sum:=#sum+valus,#sum:=(#sum+valus) / 3) rt, if(#count=3,#count:=0,#count:=#count) creset, if(#count=0,#sum:=0,#sum:=#sum) sumreset from t cross join (select #m ='',#count:=0,#sum:=0,#block:=0,#mth:='') s order by id )t where counter = 3; +----+--------+------+ | id | mth | rt | +----+--------+------+ | 3 | Mar-14 | 51 | | 6 | Jun-14 | 54 | | 9 | Sep-14 | 57 | +----+--------+------+ 3 rows in set (0.03 sec) Slightly less messy but using sql's avg function and using variables to fill down the first month in a 3 month block select block,mth,avg(valus) from ( select id,month,valus, #count:=#count+1 counter, if(#count=1,#mth:=month,#mth:=#mth) mth, if(#count=1,#block:=#block+1,#block:=#block) block, if(#count=3,#count:=0,#count:=#count) creset from t cross join (select #block:=0,#count:=0,#mth:='') s order by id ) t group by block,mth order by block,mth +-------+--------+------------+ | block | mth | avg(valus) | +-------+--------+------------+ | 1 | Mar-14 | 51.0000 | | 2 | Jun-14 | 54.0000 | | 3 | Sep-14 | 57.0000 | | 4 | Dec-14 | 59.0000 | +-------+--------+------------+ 4 rows in set (0.05 sec)
Try this create temporary table tab (month1 varchar(30), id int); insert into tab (month1,id) values('Mar-14' ,50), ('Apr-14' ,51), ('May-14' ,52), ('Jun-14' ,53), ('Jul-14' ,54), ('Aug-14' ,55), ('Sep-14' ,56), ('Oct-14' ,57), ('Nov-14' ,58), ('Dec-14' ,59), ('Jan-15' ,60), ('Feb-15' ,61), ('Mar-14' ,62); set #row_number = 0; select * from tab where (#row_number := #row_number+1)%3= 1; Result month1 id 'Mar-14' '50' 'Jun-14' '53' 'Sep-14' '56' 'Dec-14' '59' 'Mar-14' '62'
Match column name to data in MYSQL
I have data like in table. Item | 7/7/15 | 7/8/15 | 7/9/15 1 | 23 | 24 | 25 2 | 26 | 74 | 96 and I have table which has, Item | Date | Number 1 | 7/9/15 | 56 1 | 7/7/15 | 75 1 | 7/8/15 | 63 I want to find sum of Number from 7/7/15 to 7/8/15 from table 1 and sum of the number from second table. My table should look like Item | StartDate | EndDate | no. | TotalNumber
item 7/7/15 7/8/15 7/9/15 1 23 24 25 2 26 74 96 item date number 1 7/9/15 56 1 7/7/15 75 1 7/8/15 63 . SELECT i1.Item, '7/7/15' AS "StartDate", '7/8/15' AS "EndDate", (SELECT SUM(`7/7/15`)+SUM(`7/8/15`) FROM table1 WHERE item=i1.item) AS no, (SELECT SUM(number) FROM table2 WHERE item=i1.item) "TotalNumber" FROM table2 i2 RIGHT OUTER JOIN table1 i1 on i1.item=i2.item; item startdate enddate no TotalNumber 1 7/7/15 7/8/15 47 194 1 7/7/15 7/8/15 47 194 1 7/7/15 7/8/15 47 194 2 7/7/15 7/8/15 100 . It's working..
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/