I have this query which is working fine:
SELECT c.id, c.name
FROM job j
LEFT JOIN portfolio_job_category pjc ON pjc.job_id = j.id
LEFT JOIN category c ON c.id = pjc.category_id
WHERE j.end_date >= DATE( NOW( ) )
AND pjc.portfolio_id =3
GROUP BY c.id
ORDER BY `c`.`id` ASC
LIMIT 0 , 30
But when I do query below it doesn't work and returns empty rows:
SELECT c.id, c.name
FROM commstratjobs.job j
LEFT JOIN commstratjobs.portfolio_job_category pjc ON pjc.job_id = j.id
LEFT JOIN commstratjobs.category c ON c.id = pjc.category_id
WHERE j.end_date >= DATE( NOW( ) )
AND pjc.portfolio_id =3
GROUP BY c.id
ORDER BY c.name;
LIMIT 0 , 30
Is there a reason why?
Only thing I did was to add database in front of tables...
did you try to seprate database & table by this symbol : `
i.e
commstratjobs.job
so your query will be like this
SELECT c.id, c.name
FROM `commstratjobs`.`job j`
LEFT JOIN `commstratjobs`.`portfolio_job_category` pjc ON pjc.job_id = j.id
LEFT JOIN `commstratjobs`.`category` c ON c.id = pjc.category_id
WHERE j.end_date >= DATE( NOW( ) )
AND pjc.portfolio_id =3
GROUP BY c.id
ORDER BY c.name;
LIMIT 0 , 30
Related
Hello i have this query and I need to access de artist_id inside subquery. but don't work.
SELECT g.name, SUM(l.month_start_value), GROUP_CONCAT(l.artist_id), GROUP_CONCAT(l.month_start_value)
FROM genre g
LEFT JOIN genre_artist ga ON g.id = ga.genre_id
LEFT JOIN artist a ON ga.artist_id = a.id
LEFT JOIN (SELECT artist_id,
(SELECT CAST(value as SIGNED)
FROM platform_information_artist
WHERE platform_information_id =
(SELECT id from platform_information WHERE platform = 'spotify' AND information = 'monthly_listeners')
and artist_id = a.id
AND DATE(date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY date ASC
LIMIT 1) as month_start_value
FROM platform_information_artist
GROUP BY platform_information_artist.artist_id) l ON a.id = l.artist_id
GROUP BY g.id
ORDER BY g.id ASC;
The line that's wrong is
and artist_id = a.id
Returns this error: [42S22][1054] Unknown column 'a.id' in 'where clause'
I don't know why I can't access to a.id inside subquery.
There's a number of ways to do this. The least change from your current query is to simply change a couple of references:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(l.artist_id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN
( SELECT pia.artist_id,
( SELECT CAST(pia2.value as SIGNED)
FROM platform_information_artist AS pia2
WHERE pia2.platform_information_id = (SELECT id
FROM platform_information
WHERE platform = 'spotify'
AND information = 'monthly_listeners')
AND pia2.artist_id = pia.artist_id
-- ^^ Updated from `a.id` to `pia.artist_id`
AND DATE(pia2.date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY pia2.date ASC
LIMIT 1
) as month_start_value
FROM platform_information_artist AS pia
GROUP BY pia.artist_id
) l
ON a.id = l.artist_id
GROUP BY g.id
ORDER BY g.id ASC;
This version should work in most versions of MySQL.
If you are using newer versions of MySql though you have a couple more options, which are both more efficient than the above. The first is to use a lateral join:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(a.id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN LATERAL
( SELECT CAST(pia.value as SIGNED) AS month_start_value
FROM platform_information_artist AS pia
INNER JOIN platform_information AS i
ON i.id = pia.platform_information_id
WHERE i.platform = 'spotify'
AND i.information = 'monthly_listeners'
AND pia.artist_id = a.id
AND DATE(pia.date) >= DATE(NOW()) - INTERVAL 30 DAY
ORDER BY pia.date ASC
LIMIT 1
) AS l
ON 1= 1
GROUP BY g.id
ORDER BY g.id ASC;
The other is to use ROW_NUMBER() rather than limit to select one value per artist:
SELECT g.name AS genre,
SUM(l.month_start_value) AS SumStartValue,
GROUP_CONCAT(l.artist_id) AS ArtistIDs,
GROUP_CONCAT(l.month_start_value) AS MonthStartValues
FROM genre g
LEFT JOIN genre_artist AS ga
ON g.id = ga.genre_id
LEFT JOIN artist AS a
ON ga.artist_id = a.id
LEFT JOIN
( SELECT pia.artist_id,
CAST(pia.value as SIGNED) AS month_start_value,
ROW_NUMBER() OVER(PARTITION BY pia.artist_id ORDER BY pia.Date) AS RowNum
FROM platform_information_artist AS pia
INNER JOIN platform_information AS i
ON i.id = pia.platform_information_id
WHERE i.platform = 'spotify'
AND i.information = 'monthly_listeners'
AND DATE(pia.date) >= DATE(NOW()) - INTERVAL 30 DAY
) AS l
ON l.artist_id = a.id
AND l.RowNum = 1
GROUP BY g.id
ORDER BY g.id ASC;
Examples of all 3 on db<>fiddle
I am learning to use MySQL query inside a Python project.
I am using MySQLDB module in Python to upload and data to my MySQL database and now, I want to compare data and print out the difference.
I have 3 tables(only included relevant columns):
name
rawid
origid
name
rawdata
rawid
date
total
origdata
origid
date
total
I need to compare 'total' of the same person depending on the date.
e.g. From 2020-05-02 to 2020-05-09, I want to print origid, rawid, name, date, and total if the origdata total and rawdata total does not match for the matching date and person.
What is the query I can compare and return relevant information?
What I want to accomplish is something similar to the following:
SELECT n.name
, o.date
, o.total
, r.total raw_total
FROM origdata o
LEFT
JOIN name n
ON n.origid = o.origId
LEFT
JOIN rawdata r
ON r.rawId = n.rawId
WHERE o.date >= '2020-05-02'
AND o.date < '2020-05-10'
GROUP
BY o.origId
, o.date
When this is ran, rawdata.total does not show correct values; value of origdata.total and rawdata.total should be the same.
Thank you so much for the help!
If your "date" column is DATETIME type, you could use CAST:
SELECT n.name
, o.date
, o.total
, r.total raw_total
FROM origdata o
LEFT
JOIN name n
ON n.origid = o.origId
LEFT
JOIN rawdata r
ON r.rawId = n.rawId
WHERE CAST(o.date AS DATE) BETWEEN '2020-05-02' AND '2020-05-10'
GROUP
BY o.origId
, o.date
As you probably have records in the same table with the same date, first you need to aggregate them (Group By - Sum)
SELECT n.name, o.date,
o.total as orig_total,
r.total as raw_total
FROM
(
select o.origid, o.date, sum(o.total) as total
from origdata o
group by o.origid, o.date
) o
JOIN
(
select r.rawid, r.date, sum(r.total) as total
from rawdata r
group by r.rawid, r.date
) r
on o.origid = r.rawid
and o.date = r.date
LEFT JOIN name n
on o.origid = n.origid
and r.rawid = n.rawid
WHERE o.date >= '2020-05-02'
and o.date < '2020-05-10'
and not o.total = r.total
Consider that this will only return coincident dates in both tables. If you want to include null date values, you need to use a LEFT AND RIGHT JOIN, because MySql does not support OUTER JOINS
SELECT n.name, o.date,
o.total as orig_total,
r.total as raw_total
FROM (
select o.origid, o.date, sum(o.total) as total
from origdata o
group by o.origid, o.date
) o
LEFT JOIN (
select r.rawid, r.date, sum(r.total) as total
from rawdata r
group by r.rawid, r.date
) r
on o.origid = r.rawid
and o.date = r.date
LEFT JOIN name n
on o.origid = n.origid
and r.rawid = n.rawid
WHERE r.rawid is null
and o.date >= '2020-05-02'
and o.date < '2020-05-10'
UNION
SELECT n.name, r.date,
o.total as orig_total,
r.total as raw_total
FROM (
select o.origid, o.date, sum(o.total) as total
from origdata o
group by o.origid, o.date
) o
RIGHT JOIN (
select r.rawid, r.date, sum(r.total) as total
from rawdata r
group by r.rawid, r.date
) r
on o.origid = r.rawid
and o.date = r.date
LEFT JOIN name n
on o.origid = n.origid
and r.rawid = n.rawid
WHERE o.origid is null
and r.date >= '2020-05-02'
and r.date < '2020-05-10'
NOTE: one way to do it would be using CTE, but prior to version 8, MySql does not support that. then I tried using temporary tables to make it easier, but apparently the same temp_table cannot be read twice in the same statement, giving me a Error Code: 1137. Can't reopen table 'o' (I'm using MySql 5.7)
CREATE TEMPORARY TABLE IF NOT EXISTS temp_origdata AS
(
select o.origid, o.date, sum(o.total) as total
from origdata o
group by o.origid, o.date
)
CREATE TEMPORARY TABLE IF NOT EXISTS temp_rawdata AS
(
select r.rawid, r.date, sum(r.total) as total
from rawdata r
group by r.rawid, r.date
)
SELECT n.name, o.date,
o.total as orig_total,
r.total as raw_total
from temp_origdata o
left join temp_rawdata r
on o.origid = r.rawid
and o.date = r.date
LEFT JOIN name n
on o.origid = n.origid
and r.rawid = n.rawid
where r.rawid is null
and o.date >= '2020-05-02'
and o.date < '2020-05-10'
union
SELECT n.name, o.date,
o.total as orig_total,
r.total as raw_total
from temp_origdata o
right join temp_rawdata r
on o.origid = r.rawid
and o.date = r.date
LEFT JOIN name n
on o.origid = n.origid
and r.rawid = n.rawid
where o.origid is null
and r.date >= '2020-05-02'
and r.date < '2020-05-10'
I have this SQL query that returns me the whole set:
SELECT s.id, s.status, s.created_at
FROM scores s
WHERE s.account_id IN (
SELECT a.id
FROM accounts a
WHERE a.status = 'ACTIVE' AND a.created_at >= DATE(NOW()) - 3 AND a.tool = 'GLR'
) ORDER BY s.created_at ASC;
...but now I want a sub-set of that: all the records in account that doesn't have any record in score.
I've tried these, but no luck so far O:)
--- Using LEFT JOIN
SELECT s.account_id, s.status, s.created_at
FROM scores s
LEFT JOIN accounts a ON s.account_id = a.id
AND a.status = 'ACTIVE'
AND a.created_at >= DATE(NOW()) - 3
AND a.tool = 'GLR'
WHERE s.account_id IS NULL ORDER BY s.created_at ASC;
--- Using EXISTS / NOT EXISTS
SELECT s.account_id, s.status, s.created_at
FROM scores s
WHERE NOT EXISTS (
SELECT 1 FROM accounts a
WHERE s.account_id = a.id
AND a.status = 'ACTIVE'
AND a.created_at >= DATE(NOW()) - 3
AND a.tool = 'GLR'
) ORDER BY s.created_at ASC;
SELECT a.* FROM accounts a LEFT JOIN scores s ON s.account_id = a.id
WHERE a.status = 'ACTIVE' AND a.created_at >= DATE(NOW()) - 3 AND a.tool = 'GLR'
AND s.account_id IS NULL
SELECT DISTINCT (
A.`id`
), A.`id` , A.`no` , B.amount, SUM( A.`outward` * A.`price` ) AS total, A.`outward_date`
FROM `outward` A
INNER JOIN franchisees B
INNER JOIN store C
INNER JOIN shoppe D
WHERE B.user_id = C.user_id
AND (C.pos_id = A.no)//(C.pos_id = A.no OR (D.id = A.no)
OR (D.id = A.no)
AND A.outward_date = '2012-02-10'
GROUP BY A.req_id
ORDER BY A.no ASC , A.`d` ASC , B.amount ASC
The problem in this query is that the SUM( A.outward * A.price ) AS total comes differently which is not related to
ouptut
id sum(outward * price)
12021030738-105 485.220000000000
1202104186-104 2504.410000000000
output displayed
12021030738-105 32557.33
1202104186-104 6307.86
i guess the problem is with the OR statement? can anyone find the issue with the query
Try below. enclose OR Conditions in a parenthesis:
SELECT DISTINCT (
A.`id`
), A.`id` , A.`no` , B.amount, SUM( A.`outward` * A.`price` ) AS total, A.`outward_date`
FROM `outward` A
INNER JOIN franchisees B
INNER JOIN store C
INNER JOIN shoppe D
WHERE B.user_id = C.user_id
AND ((C.pos_id = A.no) OR (D.id = A.no))
AND A.outward_date = '2012-02-10'
GROUP BY A.req_id
ORDER BY A.no ASC , A.`d` ASC , B.amount ASC
I want to do the following using a LEFT JOIN (please do not suggest UNION ALL)
SELECT o.*, s.col1, s.col2 FROM order o
INNER JOIN user u ON o.user_id = u.id
IF o.date less than '2011-01-01'
JOIN subscribe s ON u.key = s.key
ELSE
JOIN subscribe s ON u.email = s.email
END IF;
I used the following but can't test it.
SELECT o.*, COALESCE(s1.col1,s2.col1) AS
col1, COALESCE(s1.col2, s2.col2) AS col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s1 ON
(u.key LIKE (CASE o.date >= '2011-01-01 00:00:00'
WHEN TRUE THEN s1.key ELSE NULL END))
LEFT JOIN subscribe s2 ON (u.email LIKE (CASE o.date <
'2011-01-01 00:00:00' WHEN TRUE THEN s.email
ELSE NULL END));
Please correct me if I am wrong.
Thanks.
You don't need to JOIN twice, do it like this:
SELECT o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( ( o.date < '2011-01-01' AND u.key = s.key ) OR
( o.date >= '2011-01-01' AND u.email = s.email ) )
And here is a solution that will not do a full table scan if you have indexes on subscribe.key and subscribe.email:
SELECT * FROM
(
( SELECT 0 AS mode, o.date AS odate, o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( u.key = s.key ) )
UNION
( SELECT 1 AS mode, o.date AS odate, o.*, s.col1, s.col2
FROM order o INNER JOIN user u ON o.user_id = u.id
LEFT JOIN subscribe s ON( u.email = s.email ) )
)
WHERE ( odate < '2011-01-01' AND mode = 0 ) OR
( odate >= '2011-01-01' AND mode = 1 )