Using inner joins and aliases in mysql - mysql

I'm trying to join several different values from the same table. I'm trying to return printing rates in the query from different time horizons (how much has been printed in the month/day/year/week etc.) and I am getting a 1064 error when I execute the query below. What could the explanation be?
SELECT t1.station_name, t1.yearpages, t2.monthpages
FROM (
SELECT station_name, SUM(print_pages) yearpages
FROM `file_prints`
WHERE year(print_date) = 2014;
) t1
INNER JOIN (
SELECT station_name, sum(print_pages) monthpages
FROM `file_prints`
WHERE month(print_date) = 2;
) ON t1.station_name = t2.station_name;
Then, if I were to add multiple joins, would the query look like this?
SELECT t1.station_name, t1.station_name as db_name, t1.yearpages, t2.monthpages, t3.daypages, t4.weekpages
FROM (
SELECT station_name, sum(print_pages) yearpages
FROM `file_prints`
WHERE year(print_date) = $year;
GROUP BY station_name
) t1
INNER JOIN (
SELECT station_name, sum(print_pages) monthpages
FROM `file_prints`
WHERE month(print_date) = $month;
GROUP BY station_name
) t2 ON t1.station_name = t2.station_name
INNER JOIN (
SELECT station_name, sum(print_pages) daypages
FROM `file_prints`
WHERE dayofmonth(print_date) = $day;
GROUP BY station_name
) t3 ON t2.station_name = t3.station_name
INNER JOIN (
SELECT station_name, sum(print_pages) weekpages
FROM `file_prints`
WHERE week(print_date) = $week;
GROUP BY station_name
) t4 ON t3.station_name = t4.station_name

How about just using conditional aggregation?
SELECT station_name,
sum(case when year(print_date) = $year then print_pages end) as yearpages,
sum(case when month(print_date) = $month then print_pages end) as monthpages,
sum(case when day(print_date) = $day then print_pages end) as daypages,
sum(case when week(print_date) = $week then print_pages end) as weekpages
FROM `file_prints`
GROUP BY station_name;

Related

Query optimization needed because of too many sub queries and sub query dependency in where conditions

I'm writing code for the production report.
I had written this query
SELECT
P.*,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_prod,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date < '2019-11-01' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS before_dispatched,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
create_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production,
(
SELECT
COUNT(id) AS cnt
FROM
bales
WHERE
(
dispatched = '0' OR disp_bunch = '0'
) AND dispatch_date BETWEEN '2019-11-01' AND '2019-11-06' AND product_id = P.id AND(TYPE = 'bale' OR TYPE = 'bag')
) AS production_dispatched,
C.name AS category_name
FROM
products P
INNER JOIN category C ON
C.id = P.category
This query is working but as I have too many records in all tables it takes too much time.
also, I need only records where before_prod, before_dispatched, production, production_dispatched all these subquery results should be greater than 0.
I tried to use having clause but it also takes too much time.
I have also tried php for loop, * LOGIC: first all products than in for loop its production. but it was much slower.*
How can I optimize my query?
You can use join instead and select case to sum your data that matches your conditions.
select p.*, t.*
from products p
inner join (
select t2.id, sum(case when create_date < '2019-11-01' then 1 else 0 end) as before_prod
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date < '2019-11-01' then 1 else 0 end) as before_dispatched
, sum(case when create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production
, sum(case when (dispatched = '0' or disp_bunch = '0') and create_date between '2019-11-01' and '2019-11-06' then 1 else 0 end) as production_dispatched
from bales t1
inner join product t2 on t2.id= t1.product_id
inner join category t3 on t3.id = t2.category
where t1.TYPE in ('bale', 'bag')
group by t2.id) t
on t.id = p.id

MySQL select query, adding max value from another table

Trying to add another column with a new table, would appreciate any help/suggestions!
Current query:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
And that works fine, gives 1 row of results. I'd now like to add another column to the results, I believe a left outer join from the prices table of the record that is the closest date before 2017-12-31. My attempt:
SELECT parent.name AS parentname, a.name AS accname,
parent.code AS parentcode, a.code AS acccode,
parent.guid AS parentguid, a.guid AS accguid,
a.account_type AS accttype,
sum(case when date_format(post_date, '%Y-%m-%d') <= '2017-12-31' then (s.value_num/s.value_denom) else '0' end) AS 'value2017-12-31',
sum(case when date_format(post_date, '%Y-%m-%d') <= '2018-01-25' then (s.value_num/s.value_denom) else '0' end) AS 'value2018-01-25',
MAX(case when date_format(p.date, '%Y-%m-%d') <= '2017-12-31' then (p.value_num/p.value_denom) else '0' end) AS 'price2017-12-31'
FROM transactions AS t INNER JOIN splits AS s ON s.tx_guid = t.guid
INNER JOIN accounts AS a ON a.guid = s.account_guid
INNER JOIN accounts AS parent ON parent.guid = a.parent_guid
LEFT OUTER JOIN prices as p ON p.commodity_guid = a.commodity_guid
WHERE a.hidden = 0 AND a.account_type NOT IN ('INCOME', 'EXPENSE')
AND parent.name <>''
AND a.guid = '3f3fc442a98225f481bb72e0fd526cbb'
GROUP by accname, parentname ORDER by acccode
It's obviously incorrect as it's now changing the values of value2017-12-31 and value2018-01-25. I get the price correctly using a separate query:
SELECT p.value_num/p.value_denom as calcprice
FROM `prices` as p
WHERE commodity_guid = '77be249d12d9889e90f08dde7c671eb0'
AND date_format(p.date, '%Y-%m-%d') <= '2017-12-31'
order
by date DESC
limit 1
Is there any way to combine them rather than using temp tables?

How to create codeigniter query from below sql query?

I've a query like this which is working fine but I want to create a pure CI query from this. I'm new in CI so can anyone help me to figure out how this can be done or suggest me a reference website or link from where i can get help. Thanks
SELECT
user_des,
IFNULL((sent),0) as sent,
IFNULL((viewed),0) as viewed,
CONCAT(IFNULL(fname_usr,user_des),' ',lname_usr,user_des) as fullname,
IFNULL(sum(duration),0) as totalviewtime,
IFNULL((totalviews),0) as views,
IFNULL(sum(sharedcount),0) as shares,
IFNULL(sum(shared),0) as shared
FROM dem_senddemo
INNER JOIN
(SELECT * FROM dem_demos WHERE id_dem IN (746,943,748) AND customer_dem = '1') as demosfiltered
ON demo_des = id_dem
LEFT JOIN
(
(
Select senddemo_wis, sum(duration) as duration, max(datereceived_wis) as datereceived_wis
FROM
(
select senddemo_wis, invited_wis, sum(IFNULL(duration_fea,0) * IFNULL(percentviewed_wis,0)) as duration, max(datereceived_wis) as datereceived_wis
FROM (sta_views
LEFT JOIN sta_featureswisitavisits as s ON visit_fvi = id_vis
LEFT JOIN
(
(SELECT shortvideovid_fea as videoid_fea, shortvideoduration_fea as duration_fea
FROM dem_features
where shortvideoduration_fea > 0)
UNION
(SELECT longvideovid_fea as videoid_fea, longvideoduration_fea as duration_fea
FROM dem_features
where longvideoduration_fea > 0)
) as x
ON videoid_fea = showedvideo_fvi)
LEFT JOIN
sta_wistia as w ON invited_fvi = invited_wis AND s.showedvideo_fvi = w.mediaid_wis AND wistia_vis = email_wis
WHERE countvisit_wis <> 'N'
GROUP BY invited_wis
) as durfea
GROUP BY senddemo_wis
) UNION
(
SELECT senddemo_wis,sum(IFNULL(mainvideoduration_dem ,0) * IFNULL(percentviewed_wis,0)) as duration, max(datereceived_wis) as datereceived_wis
FROM sta_wistia as w
INNER JOIN
(select *, customer_dem as cuss FROM dem_demos) as demcorp ON demo_wis = id_dem AND mainmessagingvideovid_dem = w.mediaid_wis
LEFT JOIN sta_views ON email_wis = wistia_vis
WHERE customer_dem = 1 AND senddemo_wis > 0 AND countvisit_wis <> 'N'
GROUP BY senddemo_wis
)
) as c ON id_des = senddemo_wis
LEFT JOIN
(
SELECT user_des as user2_des, count(id_vis) as totalviews
FROM sta_views
LEFT JOIN dem_invited ON id_invited = invited_vis
LEFT JOIN dem_senddemo ON id_des = id_senddemo
WHERE NOT ISNULL(id_senddemo) AND countvisit_wis != 'N' AND createdon_des BETWEEN '2015-05-31 00:00:00' AND '2015-06-29 23:59:59' AND demo_des IN (746,943,748)
GROUP BY user_des
) as z ON user_des = user2_des
LEFT JOIN
(
SELECT user_des as user3_des, count(id_des) as sent
FROM dem_senddemo
LEFT JOIN dem_invited ON id_senddemo = id_des
WHERE createdon_des BETWEEN '2015-05-31 00:00:00' AND '2015-06-29 23:59:59' AND demo_des IN (746,943,748) AND first_invited = 'YES'
GROUP BY user_des
) as za ON user_des = user3_des
LEFT JOIN
(
SELECT user_des as user4_des, count(id_vis) as viewed
FROM sta_views LEFT JOIN dem_invited ON id_invited = invited_vis
LEFT JOIN dem_senddemo ON id_des = id_senddemo
WHERE NOT ISNULL(id_senddemo) AND countvisit_wis != 'N' AND createdon_des BETWEEN '2015-05-31 00:00:00' AND '2015-06-29 23:59:59' AND state = 'VIEWED'
AND first_invited = 'YES' AND demo_des IN (746,943,748)
GROUP BY user_des
) as zb ON user_des = user4_des
LEFT JOIN
(
SELECT id_senddemo as iddemdemos2, count(id_senddemo) as shared, allshares as sharedcount
FROM
(
SELECT id_senddemo, count(id_senddemo) as allshares
FROM dem_invited
LEFT JOIN dem_senddemo on id_senddemo = id_des
WHERE first_invited <> 'YES' AND demo_des IN (746,943,748)
GROUP BY id_senddemo
) as x
GROUP BY id_senddemo
) as zc ON iddemdemos2 = id_des
LEFT JOIN
sec_users ON user_des = id_usr
WHERE customer_dem = 1 AND createdon_des BETWEEN '2015-05-31 00:00:00' AND '2015-06-29 23:59:59'
GROUP BY user_des

MySQL derived table with join

In the following query I'm having a problem when it comes to returning the right value for count2.
What I need is to get the number of rows from table2 which could easily be done by using a derived table t:
SELECT name,
(SELECT COUNT(*) FROM `table1`) AS count1,
(SELECT COUNT(*) FROM (
SELECT COUNT(*) FROM `table2` t2) WHERE t2.user = prf.user)
) t AS count2,
(SELECT SUM(a) FROM `table3`) AS count3
FROM `profiles` prf
WHERE 1=1
AND prf.user = 1
The problem is that the WHERE t2.user = prf.user statement fails as the prf table is outside the subquery's scope.
How can I achieve the above?
EDIT: I'm adding the actual query in case it's helpful for getting a better grasp:
SELECT PRF.BranchID, PRF.user_id, CONCAT_WS(" ",PRF.lastname,PRF.firstname) Synergatis,
( SELECT COUNT(*) FROM Actions A JOIN Requests R ON R.RequestID=A.RequestID WHERE A.ActionStatus = 302 AND A.UserOwner = PRF.user_id AND A.ActionDate BETWEEN '2015-06-01' AND '2015-06-10' ) AS energeies,
( SELECT COUNT(DISTINCT RPP.RequestID) FROM VW_Xartofylakio_Synergati VV JOIN Requests_Prop RPP ON RPP.PropertyID = VV.PropertyID JOIN Requests R ON R.RequestID = RPP.RequestID WHERE VV.CurrUsr = PRF.user_id AND R.ModifyTime BETWEEN '2015-06-01' AND '2015-06-10' ) AS zitiseis_eidikes,
( SELECT COUNT(DISTINCT(CustomerID)) FROM Demo_Orders_M WHERE DemoOrderStatus=253 AND USER=PRF.user_id AND DemoOrderDate BETWEEN '2015-06-01' AND '2015-06-10' ) AS endiaferomenoi,
( SELECT COUNT(*) AS cnt FROM Demo_Orders_M DOM JOIN Actions A ON DOM.DemoOrderID = A.DemoOrderID WHERE DOM.User = PRF.user_id AND DOM.DemoOrderStatus = 253 AND A.ActionDate BETWEEN '2015-06-01 14:56:19' AND '2015-06-30 14:56:19' GROUP BY DOM.CustomerID, DOM.User HAVING COUNT(*) > 1 ) AS anakykl_endiaf,
( SELECT COUNT(*) FROM Demo_Orders_M DOM WHERE DOM.`User`=PRF.user_id AND DemoOrderStatus = 253 AND DOM.DemoOrderDate BETWEEN '2015-06-01' AND '2015-06-10' ) AS epideixeis,
( SELECT COUNT(DISTINCT(DOD.PropertyID)) AS PropertyID FROM Demo_Orders_M DOM JOIN Demo_Orders_D DOD ON DOM.DemoOrderID = DOD.DemoOrderID JOIN Actions A ON DOD.DemoOrderID = A.DemoOrderID WHERE DOM.DemoOrderStatus = 253 AND DOM.User = PRF.user_id AND A.ActionDate BETWEEN '2015-06-01' AND '2015-06-10' ) AS monadika_akinita
FROM tbl_profiles PRF
WHERE 1=1
AND PRF.user_id IN (
SELECT a.user_id FROM tbl_profiles a WHERE a.user_id IN ('248','1159','486','183')
OR a.GroupID IN (SELECT b.GroupID FROM L_Groups b WHERE b.ManagerID IN ('248','1159','486','183'))
)
ORDER BY PRF.user_id
The subquery I'm referring to is the one that returns the result as anakykl_endiaf.
I suspect it is not because of prf table, it is because of t2 table... There are no restrictions to use outer alias in inner subqueries because there are such a thing like correlated subquery. Your problem is that you have the opposite case here: you are referring inner alias in outer query.
(SELECT COUNT(*)
FROM (SELECT COUNT(*) FROM `table2` t2) WHERE t2.user = prf.user)
Why are you selecting count twice here? You can change to this:
(SELECT COUNT(*)
FROM (SELECT COUNT(*) FROM `table2` t2 WHERE t2.user = prf.user))
or this:
(SELECT COUNT(*)
FROM `table2` t2 WHERE t2.user = prf.user)
A suggestion to try.
You have sub queries in the SELECT, and in this case they must each only return a single row. For some reason (which we can't really tell without test data) one of these is returning more than 1 row, hence failing.
As an interim step, change the query to join against the sub queries, which should make it more obvious when there are duplicates (and may also be quite a bit more efficient, depending on the data).
Something like this (not tested so probably a few typos):-
SELECT PRF.BranchID,
PRF.user_id,
CONCAT_WS(" ",PRF.lastname,PRF.firstname) Synergatis,
ar.energeies,
vrr.zitiseis_eidikes,
m.endiaferomenoi,
ae.anakykl_endiaf,
d.epideixeis,
ddd.monadika_akinita
FROM tbl_profiles PRF
LEFT OUTER JOIN
(
SELECT A.UserOwner AS DomUser, COUNT(*) AS energeies
FROM Actions A
JOIN Requests R ON R.RequestID=A.RequestID
WHERE A.ActionStatus = 302
AND A.ActionDate BETWEEN '2015-06-01' AND '2015-06-10'
GROUP BY A.UserOwner
) ar
ON ar.DomUser = PRF.user_id
LEFT OUTER JOIN
(
SELECT VV.CurrUsr AS DomUser, COUNT(DISTINCT RPP.RequestID) AS zitiseis_eidikes
FROM VW_Xartofylakio_Synergati VV
JOIN Requests_Prop RPP ON RPP.PropertyID = VV.PropertyID
JOIN Requests R ON R.RequestID = RPP.RequestID
WHERE R.ModifyTime BETWEEN '2015-06-01' AND '2015-06-10'
GROUP BY VV.DomUser
) vrr
ON vrr.DomUser = PRF.user_id
LEFT OUTER JOIN
(
SELECT `USER` AS DomUser, COUNT(DISTINCT(CustomerID)) AS endiaferomenoi
FROM Demo_Orders_M
WHERE DemoOrderStatus=253
AND DemoOrderDate BETWEEN '2015-06-01' AND '2015-06-10'
GROUP BY DomUser
) m
ON PRF.user_id = m.DomUser
LEFT OUTER JOIN
(
SELECT DOM.CustomerID, DOM.`User` AS DomUser, COUNT(*) AS anakykl_endiaf
FROM Demo_Orders_M DOM
JOIN Actions A ON DOM.DemoOrderID = A.DemoOrderID
WHERE DOM.DemoOrderStatus = 253
AND A.ActionDate BETWEEN '2015-06-01 14:56:19' AND '2015-06-30 14:56:19'
GROUP BY DOM.CustomerID, DOM.DomUser
HAVING COUNT(*) > 1
) ae
ON PRF.user_id = ae.DomUser
LEFT OUTER JOIN
(
SELECT DOM.`User` AS DomUser, COUNT(*) AS epideixeis
FROM Demo_Orders_M DOM
WHERE DemoOrderStatus = 253
AND DOM.DemoOrderDate BETWEEN '2015-06-01' AND '2015-06-10'
GROUP BY DOM.DomUser
) d
EDIT
If you just want a count of the number of customerID fields for a user in the anakykl_endiaf field then change it to doing a count of distinct customerIDs. Ie, for the above query I have done change it to:-
LEFT OUTER JOIN
(
SELECT DOM.`User` AS DomUser, COUNT(DISTINCT DOM.CustomerID) AS anakykl_endiaf
FROM Demo_Orders_M DOM
JOIN Actions A ON DOM.DemoOrderID = A.DemoOrderID
WHERE DOM.DemoOrderStatus = 253
AND A.ActionDate BETWEEN '2015-06-01 14:56:19' AND '2015-06-30 14:56:19'
GROUP BY DOM.DomUser
HAVING COUNT(*) > 1
) ae

mysql get distinct tokens from a string list

I have a query in mysql that group concats records and gives a value having redundant tokens. Below is the output of the query:
Problem Area->ACC-HO->ACC-HO->Credit Note (C/N)->Problem description ->Problem description
But I want the distinct tokens of this string as below
Problem Area->ACC-HO->Credit Note (C/N)->Problem description
Is there a way to do this in the sql SELECT query itself?
EDIT
Here is schema and query
Below is my query:
SELECT
t2.transaction_id AS transaction_id,
GROUP_CONCAT(
CONCAT(
t1.display_text,
'->',
(CASE (NOT EXISTS (SELECT 1 FROM mst_node a WHERE a.parent_node_id = t1.node_id))
WHEN 1 THEN t1.display_text ELSE
(SELECT b.display_text AS DISPLAY FROM mst_node b
WHERE parent_node_id = t2.node_id AND b.display_seq = t2.entered_value)
END)
)
ORDER BY t2.logtime_stamp SEPARATOR '->'
) AS display_text
FROM
mst_node t1
JOIN trn_user_log t2
ON t1.app_id = t2.app_id AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
GROUP BY transaction_id,
mobile_no
ORDER BY t2.transaction_id DESC,
t2.logtime_stamp,
t2.mobile_no
In you GROUP CONCAT add DISTINCT so it will only concatenate unique values.
SELECT GROUP_CONCAT(DISTINCT colName),....
FROM ...
WHERE ...
GROUP BY ...
SQLFiddle Demo
in your grouping clause, you can add another group by to group by this string column as well.
SELECT GROUP_CONCAT(myStringColumn),....
FROM ...
WHERE ...
GROUP BY myOtherColumn,myStringColumn
I was finally able to resolve my issue by using a UNION of two select queries and then doing a GROUP_CONCAT(DISTINCT column ORDER BY another_column).
Below is the query I used:
SELECT
transaction_id,
GROUP_CONCAT(DISTINCT display_text ORDER BY logtime_stamp SEPARATOR '->') AS display_text
FROM
(SELECT
t2.transaction_id AS transaction_id,
t2.logtime_stamp,
t1.display_text AS display_text
FROM mst_node t1
JOIN trn_user_log t2 ON t1.app_id = t2.app_id
AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
UNION
SELECT t2.transaction_id AS transaction_id,t2.logtime_stamp,
CASE(NOT EXISTS (SELECT 1 FROM mst_node a WHERE a.parent_node_id = t1.node_id))
WHEN 1 THEN NULL
ELSE (SELECT b.display_text AS display_text FROM mst_node b WHERE parent_node_id = t2.node_id AND b.display_seq = t2.entered_value)
END AS display_text
FROM mst_node t1 JOIN trn_user_log t2
ON t1.app_id = t2.app_id AND t1.node_id = t2.node_id
WHERE (t1.app_id = 105)
AND t1.parent_node_id IS NOT NULL
AND t1.save_as_default IS NULL
ORDER BY transaction_id DESC,logtime_stamp
) AS T
GROUP BY transaction_id
ORDER BY transaction_id DESC,logtime_stamp