MySql - Join not giving expected result - mysql

trying to run below query, expecting to find a match. Since my two sub-queries are same, i am expecting to find a match, which is not happening here.
select TAB_1.RUL_IDD, TAB_2.RUL_IDD
FROM
( select aaa.RUL_ID RUL_IDD from TEST_1 aaa
inner join
(
select dt,#curRank := #curRank + 1 AS rank
from (
select distinct DATE(BTCH_RUN_DTTM) dt
FROM TEST_1
where ALRT_FLG_IND = 'Y'
and PASS_IND = 'N'
and SCH_RUN_IND = 'Y'
order by DATE(BTCH_RUN_DTTM) desc
) p,
(SELECT #curRank := 0) r
order by dt desc
) zz
where DATE(aaa.BTCH_RUN_DTTM) = zz.dt
and zz.rank=1
and aaa.ALRT_FLG_IND = 'Y'
and aaa.PASS_IND = 'N'
and aaa.SCH_RUN_IND = 'Y'
) TAB_1
left outer JOIN
(
select bbb.RUL_ID as RUL_IDD from TEST_1 bbb
inner join
(
select dt,#curRank := #curRank + 1 AS rank
from (
select distinct DATE(BTCH_RUN_DTTM) dt
FROM TEST_1
where ALRT_FLG_IND = 'Y'
and PASS_IND = 'N'
and SCH_RUN_IND = 'Y'
order by DATE(BTCH_RUN_DTTM) desc
) p,
(SELECT #curRank := 0) r
order by dt desc
) zzz
on DATE(bbb.BTCH_RUN_DTTM) = zzz.dt
and zzz.rank=1
and bbb.ALRT_FLG_IND = 'Y'
and bbb.PASS_IND = 'N'
and bbb.SCH_RUN_IND = 'Y'
) TAB_2
on TAB_2.RUL_IDD = TAB_1.RUL_IDD;
Result:
enter image description here
Not getting why its not giving the expected result. TAB_2.RUL_IDD should also have same value as TAB_1.RUL_IDD. Can experts help me over here?

Related

Get last 3 records

Is there a way to get the last 3 records (red border)? Please check the screenshot.
Screenshot:
MySQL query.
SELECT icm_external_data.client_id,
icm_external_data.gsheet_tab AS source,
icm_external_data.type,
icm_external_data.name AS lead_name,
COUNT(DISTINCT icm_leads.email) AS on_month_leads,
date_format(icm_leads.date_created,'%M') AS month,
date_format(icm_leads.date_created,'%Y') AS YEAR,
#running_total := #running_total + COUNT(DISTINCT icm_leads.email) AS cumulative_sum
FROM icm_leads
LEFT JOIN icm_external_data ON icm_external_data.gsheet_id = icm_leads.gsheet_id
JOIN (SELECT #running_total := 0) r
WHERE icm_external_data.id = '29'
AND icm_leads.gsheet_id = 'xxx'
AND (icm_leads.tab_name = 'xxx' OR icm_leads.tab_name = 'xxx')
AND icm_leads.email NOT LIKE '%xxx%'
AND (icm_leads.`type` = 'forms' OR icm_leads.`type` = 'calls')
GROUP BY year(icm_leads.date_created),month(icm_leads.date_created)
You seem to want:
order by min(icm_leads.date_created) desc
limit 3 offset 1
Use the ORDER BY and LIMIT keywords.
SELECT icm_external_data.client_id,
icm_external_data.gsheet_tab AS source,
icm_external_data.type,
icm_external_data.name AS lead_name,
COUNT(DISTINCT icm_leads.email) AS on_month_leads,
date_format(icm_leads.date_created,'%M') AS month,
date_format(icm_leads.date_created,'%Y') AS YEAR,
#running_total := #running_total + COUNT(DISTINCT icm_leads.email) AS cumulative_sum
FROM icm_leads
LEFT JOIN icm_external_data ON icm_external_data.gsheet_id = icm_leads.gsheet_id
JOIN (SELECT #running_total := 0) r
WHERE icm_external_data.id = '29'
AND icm_leads.gsheet_id = 'xxx'
AND (icm_leads.tab_name = 'xxx' OR icm_leads.tab_name = 'xxx')
AND icm_leads.email NOT LIKE '%xxx%'
AND (icm_leads.`type` = 'forms' OR icm_leads.`type` = 'calls')
GROUP BY year(icm_leads.date_created),month(icm_leads.date_created)
ORDER BY icm_leads.date_created DESC
LIMIT 3 OFFSET 1

MYSQL Using Limit In Group By

I have this kind of query that need to limit by 3 in each 'region' group but it doesnt run as I expected. The 'row_number' seems not arranged accordingly.
There must be some syntax I missed out or I didnt know. If anyone can help I dump the sql Here. MYSQL version 5.0
My query :
set #type = '';
set #num = 0;
SELECT locinvaisle.Area as ar,locinvaisle.Region as rg,custlist.CustomerName as cn,custlist.Custtype ct,
SUM(data2.quantity/1000) as mtcur,
#num := if(#type = locinvaisle.Region, #num + 1, 1) as dummy_1,
#type := locinvaisle.Region as dummy_2,
#num as row_number
FROM data2
INNER JOIN custlist ON data2.customeracc = custlist.Customeraccount
INNER JOIN locinvaisle ON data2.location = locinvaisle.Location
WHERE
date1 >= DATE_FORMAT('2018-06-11', '%Y-01-01') AND date1 <= DATE_FORMAT('2018-06-11', '%Y-%m-31')
AND
data2.unit = 'KG'
AND
data2.customeracc not in (select Customeraccount from custlist WHERE Custcat = 'bcsb')
AND
locinvaisle.Area = 'peninsular'
AND
custlist.Custtype = 'others'
GROUP BY locinvaisle.Region,custlist.CustomerName
HAVING row_number < 3
ORDER BY locinvaisle.Region,mtcur desc
Results :
Desired Results(From dummy database) :
You have to do the limiting as a full subquery ("derived table") before the group by is applied. Something along these lines:
SELECT
ar, rg, cn, ct, sum(quantity)
FROM (
SELECT
#row_num :=IF(#prev_value = locinvaisle.Region, #row_num + 1, 1)AS RowNumber
, locinvaisle.Area as ar
, locinvaisle.Region as rg
, custlist.CustomerName as cn
, custlist.Custtype ct
, data2.quantity
, #prev_value := locinvaisle.Region as dummy_2,
FROM data2
INNER JOIN custlist ON data2.customeracc = custlist.Customeraccount
INNER JOIN locinvaisle ON data2.location = locinvaisle.Location
CROSS JOIN (SELECT #row_num :=1, #prev_value :='') vars
WHERE date1 >= DATE_FORMAT('2018-06-11', '%Y-01-01') AND date1 <= DATE_FORMAT('2018-06-11', '%Y-%m-31')
AND data2.unit = 'KG'
AND data2.customeracc not in (select Customeraccount from custlist WHERE Custcat = 'bcsb')
AND locinvaisle.Area = 'peninsular'
AND custlist.Custtype = 'others'
ORDER BY locinvaisle.Region,mtcur desc
) d
WHERE rowNumber <= 3
GROUP BY ar, rg, cn, ct
ORDER BY ar, rg, cn, ct
NOTE: You need to apply an ORDER BY within the subquery to facilitate the rownumber calculation, but despite this there is no guarantee that the final output will be in the desired order unless you apply a final order by clause.
Also please note that in future versions of MySQL (V8 and above) there should be a row_number() function and over() clause that can be used instead of the variables seen above.
In MySQL, you need to be careful when using variables. Two things are important:
Variables should be assigned and referenced in the same expression.
You need to be careful about the ordering of the result set.
So, try something like this:
SELECT x.*,
(#rn := IF(#r = la.Region, #num + 1,
IF(#r := la.Region, 1, 1)
)
) as rn
FROM (SELECT la.Area as ar, la.Region as rg, c.CustomerName as cn, c.Custtype ct,
SUM(data2.quantity/1000) as mtcur
FROM data2 d INNER JOIN
custlist c
ON d.customeracc = c.Customeraccount INNER JOIN
locinvaisle la
ON d.location = la.Location
WHERE date1 >= DATE_FORMAT('2018-06-11', '%Y-01-01') AND
date1 <= DATE_FORMAT('2018-06-11', '%Y-%m-31') AND
d.unit = 'KG' AND
d.customeracc not in (select Customeraccount from custlist cl WHERE cl Custcat = 'bcsb') AND
la.Area = 'peninsular' AND
c.Custtype = 'others'
GROUP BY la.Region, c.CustomerName
) x CROSS JOIN
(SELECT #r := 0, #rn := 0) params
HAVING rn <= 3;

Read the row_number

Output: https://www.dropbox.com/s/q9bjrzndbzj0l2i/test3.PNG?dl=0
How do I incorporate a query into the current code if I want to get only the Position (row_number) = 3 if lets say the Stud_ID = 4?
SET #row_num = 0;
SELECT #row_num := #row_num + 1 as Position, s.*
FROM
(
SELECT
Student.Stud_ID, Student.Stud_Name, Student.Stud_Class, SUM(Grade.Percentage) AS Points
FROM Student, Student_Subject, Grade
WHERE Student.Stud_ID = Student_Subject.Stud_ID
AND Student_Subject.Stud_Subj_ID = Grade.Stud_Subj_ID
AND Student.Stud_Form = '1'
AND Grade.Quarter = '1'
GROUP BY Student.Stud_ID
ORDER BY Points DESC
) AS s;
Thanks!!
Use a subselect over your query and filter it with your desired row number
SELECT *
FROM (
SELECT #row_num := #row_num + 1 AS `Position`, s.*
FROM
(
SELECT
Student.Stud_ID, Student.Stud_Name, Student.Stud_Class, SUM(Grade.Percentage) AS Points
FROM Student, Student_Subject, Grade
WHERE Student.Stud_ID = Student_Subject.Stud_ID
AND Student_Subject.Stud_Subj_ID = Grade.Stud_Subj_ID
AND Student.Stud_Form = '1'
AND Grade.Quarter = '1'
GROUP BY Student.Stud_ID
ORDER BY Points DESC
) AS s
CROSS JOIN (SELECT #row_num := 0) AS s1
) AS t
WHERE t.Position = 3

MySQL - Parallel merge two unrelated queries with same # of rows

I have two tables:
exam_outline_items:
jml_quiz_pool:
Of all the things I've tried, this got me the closest:
select t1.sequence, t1.title, t2.q_cat, t2.q_count
from student_pl.exam_outline_items t1
cross join pe_joomla.jml_quiz_pool t2
where t1.exam_outline_id = 5 and t1.chapter_num > 0
and t2.q_id = 1109 and t2.q_count > 0
group by title
Which produces this result:
I just need those q_cat values to be different, like they are in the 2nd query.
Thanks in advance for your help.
You have to have something to connect them with. If you don't have such a column, you can simulate one by creating a rownumber with variables.
select sequence, title, q_cat, q_count from (
select t1.sequence, t1.title, #r1 := #r1 + 1 as rownumber
from student_pl.exam_outline_items t1
, (select #r1 := 0) var_init
where t1.exam_outline_id = 5 and t1.chapter_num > 0
order by t1.sequence
) a
inner join
(
select t2.q_cat, t2.q_count, #r2 := #r2 + 1 as rownumber
from pe_joomla.jml_quiz_pool t2
, (select #r2 := 0) var_init
where t2.q_id = 1109 and t2.q_count > 0
order by t2.q_cat
) b on a.rownumber = b.rownumber;
Also note, that I used order by in those queries. In a database you have no sort order unless you explicitly set it with order by.

Select users with a difference larger than zero between the last two entries in a specific table with SQL?

Here's the SQLFiddle Link to my tables.
I basically want to select only Jack and Jill, as there is a non-zero difference between the last two nums entries of the table foo with the user being their respective names.
How is this possible?
Note: just to mention, in my foo table, I have around 100000 rows, so it would be good if there was a very quick and fast way of retrieving the data.
I prefer doing this using limit with the offset to get the two most recent values. Happily, your table has an id column for determining the order.
select user,
(select num from foo f2 where f2.user = f.user order by f2.id desc limit 1
) lastval,
(select num from foo f2 where f2.user = f.user order by f2.id desc limit 1, 2
) lastval2
from foo f
group by user
having lastval <> lastval2
Here's one way (although I think you'd be more likely to JOIN on a user's id rather than their name!?!...
SELECT u.*
FROM
( SELECT x.*, COUNT(*) rank FROM foo x JOIN foo y ON y.user = x.user AND y.id >= x.id GROUP BY x.id)a
LEFT
JOIN
( SELECT x.*, COUNT(*) rank FROM foo x JOIN foo y ON y.user = x.user AND y.id >= x.id GROUP BY x.id)b
ON b.user = a.user
AND b.num = a.num
AND b.rank = a.rank + 1
JOIN users u
ON u.user = a.user
WHERE b.id IS NULL
AND a.rank = 1;
I think this query can be rewritten as follows, which might be faster...
SELECT u.*
FROM
( SELECT id
, user
, num
, #prev_user := #curr_user
, #curr_user := user
, #rank := IF(#prev_user = #curr_user, #rank+1, #rank:=1) rank
FROM foo
JOIN (SELECT #curr_user := null, #prev_user := null, #rank := 0) sel1
ORDER
BY user
, id DESC
) a
LEFT
JOIN
( SELECT id
, user
, num
, #prev_user := #curr_user
, #curr_user := user
, #rank := IF(#prev_user = #curr_user, #rank+1, #rank:=1) rank
FROM foo
JOIN (SELECT #curr_user := null, #prev_user := null, #rank := 0) sel1
ORDER
BY user
, id DESC
) b
ON b.user = a.user
AND b.num = a.num
AND b.rank = a.rank + 1
JOIN users u
ON u.user = a.user
WHERE b.id IS NULL
AND a.rank = 1;
Based on Strawberrys 2nd solution I have tried this.
SELECT user, MIN(num) AS MinNum, MAX(num) AS MaxNum
FROM ( SELECT id
, user
, num
, #prev_user := #curr_user
, #curr_user := user
, #rank := IF(#prev_user = #curr_user, #rank+1, 1) AS rank
FROM foo
JOIN (SELECT #curr_user := null, #prev_user := null, #rank := 1) sel1
ORDER BY user, id DESC
) AS Sub
WHERE rank <= 2
GROUP BY user
HAVING MinNum != MaxNum
This is getting the details ranked as a subselect and rejecting where the rank is greater than 2 (unfortunately the user variables give strange results if you try and check this within the subselect). The results are then grouped on user and the min and max value of num are returned. If they are different then the row is returned (and as you only have 1 or 2 rows per user, the min and max will only be different if there are 2 rows returned AND they have different values).
Advantage of this is that it avoids joining 2 100000 sets against each other and also only needs to do the ranking once (although you would hope that MySQL would optimise this 2nd issue away anyway).