Subquery to by bypass where clause - mysql

Good morning, mysql query which displays cases that have a date field completed & a total row amount, I want calculate this against the total cases but unsure if I can do all this inside one query. For example the current query outputs
Aug Sep Nov Total
10 20 20 50
The code for that being
SELECT * from(
Select Count(b.CaseID) As TotDB
from tblcontacts a
Inner Join tblcases b
On a.ContactID = b.ContactAssignedTo)a
CROSS JOIN
(Select
Sum(Month(b.StatusSubmittedDate) = 8) As Aug,
Sum(Month(b.StatusSubmittedDate) = 9) As Sep,
Sum(Month(b.StatusSubmittedDate) = 10) As Oct,
Count(b.CaseID) As Total,
ROUND (100*Count(b.CaseID)/Count(b.CaseID),2) As Conversion
From
tblcontacts a Inner Join
tblcases b On a.ContactID = b.ContactAssignedTo
Where
b.StatusSubmittedDate > '2012 - 01 - 01'
Group By
a.ContactFullName With Rollup
Having
Sum(b.CaseCommission) > 0.01)b
What I need to it output is the below so I added the TotDB line above to see if that would help, it didn't. What I need to find out is can I have a column in this query that bypasses the where/having clause to display all records
Aug Sep Nov Tot TotDB %Converted
10 20 20 50 100 50%
Thanks

probably you should do like this:
select Aug,Sep, Nov, Tot,TotDB,(Tot/TotDB*1.0)*100 as '%Converted'
from
(SELECT * from(
Select Count(b.CaseDate) As TotDB
from tblcontacts a
Inner Join tblcases b
On a.ContactID = b.ContactAssignedTo)a
CROSS JOIN
(select
Sum(Month(b.StatusSubmittedDate) = 9) As Sep,
Sum(Month(b.StatusSubmittedDate) = 10) As Oct,
Sum(Month(b.StatusSubmittedDate) = 11) As Nov,
Count(b.CaseID) As Total,
From tblcontacts a
Inner Join tblcases b
On a.ContactID = b.ContactAssignedTo
Where
b.StatusSubmittedDate > '2012-01-01'
Group By
a.ContactFullName With Rollup
Having
Sum(b.CaseCommission) > 0.01)b)c

You cannot do that in one simple query.
The right way to do that, is to do a second query, without the where clause. Really.
If you MUST do this in one query, atleast use a union:
/* old query */
SELECT a,b,c from t1,t2,t3 where d=e group by a having b>f
UNION
select 'total',COUNT(*),NULL /*need the same amount of rows*/
from t1,t2,t3
And have your clientside treat the row where a='total' differently. But that's a hack. I would advise you to use two queries.

Related

Convert mySQL partition query to mySQL 5.7 Compatible query where there are two sums in one query

I have the following query that works perfectly in mysql 8:
SELECT
J.JobID, Month(WH.DateStart) as MonthCharged, Year(WH.DateStart) as YearCharged, sum(WH.Duration) as HoursWorkedInMonth, sum(WH.Duration) over (partition by J.JobID order by Month(WH.DateStart), Year(WH.DateStart)) as CumulativeJobHoursWorked
FROM
tblJob J
JOIN tblTask T ON CONCAT('JOB-', RIGHT(YEAR(J.DateCreated), 2), '-', LPAD(J.JobID, 4, '0')) = T.SourceID
LEFT JOIN xrefTasktoEmployee XT ON T.TaskID = XT.TaskID
LEFT JOIN tblWorkHistory WH ON XT.WorkHistoryID = WH.WorkHistoryID
LEFT JOIN tblRates R ON XT.rateID = R.RateID
Where WH.Duration is not NULL
Group by J.JobID, Month(WH.DateStart), Year(WH.DateStart)
And it produces the following results:
Job ID
Month Charged
Year Charged
HoursWorkedInMonth
CumulativeJobHoursWorked
1
3
2021
23.98
23.98
1
4
2021
24.98
47.96
2
3
2021
8
8
3
2
2021
8
8
4
3
2021
1
1
5
2
2021
10
10
Notice how I am summing the hours worked in the month & year for a particular job, then I need the cumulative for that Job for the year.
I can't seem to figure out how to do this in MySQL 5.7 by using variables. Does anyone have any insights?
Thanks
Here is what I finally got to work:
SELECT
J.JobID, Month(WH.DateStart) as MonthCharged, Year(WH.DateStart) as YearCharged, sum(WH.Duration) as HoursWorkedInMonth, (SELECT
sum(WH2.Duration)
FROM
tblJob J2
JOIN tblTask T2 ON CONCAT('JOB-', RIGHT(YEAR(J2.DateCreated), 2), '-', LPAD(J2.JobID, 4, '0')) = T2.SourceID
LEFT JOIN xrefTasktoEmployee XT2 ON T2.TaskID = XT2.TaskID
LEFT JOIN tblWorkHistory WH2 ON XT2.WorkHistoryID = WH2.WorkHistoryID
Where WH2.Duration is not NULL and J2.JobID = J.JobID and DATE_FORMAT(WH2.DateStart, '%m-%Y') <= DATE_FORMAT(WH.DateStart, '%m-%Y')) as CumulativeJobHoursWorked
FROM
tblJob J
JOIN tblTask T ON CONCAT('JOB-', RIGHT(YEAR(J.DateCreated), 2), '-', LPAD(J.JobID, 4, '0')) = T.SourceID
LEFT JOIN xrefTasktoEmployee XT ON T.TaskID = XT.TaskID
LEFT JOIN tblWorkHistory WH ON XT.WorkHistoryID = WH.WorkHistoryID
Where WH.Duration is not NULL
Group by J.JobID, Month(WH.DateStart), Year(WH.DateStart)

Alternatives to joins in mysql

I have a query as follows that retrieves the status for different stores in a table and displays it as different columns.
SELECT a.Store_ID,b.total as order_completed,c.total as order_cancelled,d.total as order_processed,e.total as order_failed FROM ORDER_HISTORY a
-> LEFT OUTER JOIN(select Store_ID,count(*) as total from ORDER_HISTORY where Status = 57 group by Store_ID)b on a.Store_ID = b.Store_ID
-> LEFT OUTER JOIN(select Store_ID,count(*) as total from ORDER_HISTORY where Status = 53 group by Store_ID)c on a.Store_ID = c.Store_ID
-> LEFT OUTER JOIN(select Store_ID,count(*) as total from ORDER_HISTORY where Status = 52 group by Store_ID)d on a.Store_ID = d.Store_ID
-> LEFT OUTER JOIN(select Store_ID,count(*) as total from ORDER_HISTORY where Status = 62 group by Store_ID)e on a.Store_ID = e.Store_ID
-> group by a.Store_ID;
Can anybody suggest an alternative to using joins as it affects the performance of db operations.
Create an index on ORDER_HISTORY over (Store_ID, Status), then this should be plenty fast.
SELECT
Store_ID,
status,
COUNT(*) as total
FROM
ORDER_HISTORY
GROUP BY
Store_ID,
status;
Then use your application to display the few resulting rows data in columns. Should not be hard to implement.
Another approach would be (same index as above):
SELECT
Store_ID,
SUM(CASE WHEN Status = 57 THEN 1 ELSE 0 END) AS order_completed,
SUM(CASE WHEN Status = 53 THEN 1 ELSE 0 END) AS order_cancelled,
SUM(CASE WHEN Status = 52 THEN 1 ELSE 0 END) AS order_processed,
SUM(CASE WHEN Status = 62 THEN 1 ELSE 0 END) AS order_processed
FROM
ORDER_HISTORY
GROUP BY
Store_ID;
Replace NULL values as appropriate.
Try using a trigger. Same as a stored procedure that executes when an event occurs within the database. maybe it will help you.

SQL make 2 different date types in one query

I made a query that has 3 tables: 1 with current year, last year and name of the country
As you can see the results of current year and last year are the same and that is the problem here. I want to use like. I want to make 1 query with one that has current year and one with last year.
I can use this for last year YEAR(o.date_add) = YEAR(NOW() - INTERVAL 1 YEAR)
And from current year i can use this for example: YEAR(o.date_add) = YEAR(CURRENT_DATE())
My query:
SELECT
IFNULL(SUM(DISTINCT o.total_paid_tax_excl), 0) AS CurrentYEAR,
IFNULL(SUM(DISTINCT o.total_paid_tax_excl), 0) AS LastYEAR,
IFNULL(CONCAT(l.name), 0) AS name
FROM
expoled.ps_orders o
LEFT JOIN
expoled.ps_address a ON o.id_address_delivery = a.id_address
INNER JOIN
expoled.ps_country c ON a.id_country = c.id_country
INNER JOIN
expoled.ps_country_lang l ON c.id_country = l.id_country
WHERE
l.id_lang = 7
AND o.current_state IN (3 , 4, 5, 9, 13, 15, 20, 22, 23, 24, 25, 121)
AND l.name NOT IN ('Netherlands')
GROUP BY (l.name)
I can make seperate query but i want it in 1 query how can i archief this?
I did try Union but the results stayed the same.
I want to have it like this(this one does not work!! just for example[photoshop]
I think I need to change this part of the query
SELECT
IFNULL(SUM(o.total_paid_tax_excl), 0) AS CurrentYEAR,
IFNULL(SUM(o.total_paid_tax_excl), 0) AS LastYEAR,
IFNULL(CONCAT(l.name), 0) AS name
FROM
And add this to my query
For CurrentYEAR = YEAR(o.date_add) = YEAR(CURRENT_DATE())
For LastYEAR = YEAR(o.date_add) = YEAR(NOW() - INTERVAL 1 YEAR)
I think you can try something like this (I added CASE for fields with SUM and a Where condition to extract only relevant years):
SELECT
IFNULL(SUM( CASE WHEN YEAR(CURRENT_DATE)-YEAR(o.date_date) =0 THEN o.total_paid_tax_excl ELSE 0 END), 0) AS CurrentYEAR,
IFNULL(SUM( CASE WHEN YEAR(CURRENT_DATE)-YEAR(o.date_date) =1 THEN o.total_paid_tax_excl ELSE 0 END), 0) AS LastYEAR,
IFNULL(CONCAT(l.name), 0) AS name
FROM
expoled.ps_orders o
LEFT JOIN
expoled.ps_address a ON o.id_address_delivery = a.id_address
INNER JOIN
expoled.ps_country c ON a.id_country = c.id_country
INNER JOIN
expoled.ps_country_lang l ON c.id_country = l.id_country
WHERE
l.id_lang = 7
AND o.current_state IN (3 , 4, 5, 9, 13, 15, 20, 22, 23, 24, 25, 121)
AND l.name NOT IN ('Netherlands')
AND YEAR(o.date_date) IN (YEAR(CURRENT_DATE()), YEAR(CURRENT_DATE)-1)
GROUP BY (l.name)
You can use a conditional expression (if() function or case statement) within the sum() aggregate function to add only those values that fit the criteria:
SELECT
IFNULL(SUM(DISTINCT if(YEAR(o.date_add) = YEAR(CURRENT_DATE()),o.total_paid_tax_excl, 0)), 0) AS CurrentYEAR,
IFNULL(SUM(DISTINCT if(YEAR(o.date_add) = YEAR(CURRENT_DATE())-1,o.total_paid_tax_excl, 0)), 0) AS LastYEAR,
IFNULL(l.name, '') AS name
FROM
expoled.ps_orders o
LEFT JOIN
expoled.ps_address a ON o.id_address_delivery = a.id_address
INNER JOIN
expoled.ps_country c ON a.id_country = c.id_country
INNER JOIN
expoled.ps_country_lang l ON c.id_country = l.id_country
WHERE
l.id_lang = 7
AND o.current_state IN (3 , 4, 5, 9, 13, 15, 20, 22, 23, 24, 25, 121)
AND l.name NOT IN ('Netherlands')
GROUP BY IFNULL(l.name, '')
I also simplified the expression for the name field and made the group by clause consistent with it.
I did not change any other parts of the query, although I do not really agree with the distinct within the sum(), since you could have the same value paid as tax, but it is your data.
If your table has older data than the previous year's, then consider adding a where criteria to restrict the records for which the calculations are run.

SQL - Subquery Error and Sum Error

The SQL code I have is shown below. The issue I am having is with the subquery first of all.
The result displays the error:
SQL ERROR: Subquery returned more than 1 value. This is not permitted
when the subquery follows =, !=, <, <= , >, >= or when the subquery is
used as an expression
Need to show rows with date greater than (or equal to) the date where ESource = Detail - The rows need to be summed in some columns and a single value selected in others.
Code used:
select DISTINCT
A.Policy,
A.Fund,
(SUM(A.AddUnits)) AS SUM,
((C.TotalUnits - (SUM(A.AddUnits))) * A.Price) AS Value,
Inner JOIN TableC C
ON C.PolicyNumber = A.PolicyNumber
where A.PolicyNumber = '120' AND C.NumberOfUnits > 0 AND C.InvestmentFund = A.InvestmentFund
AND A.DateOfEntry < DATEADD(year, -1, GetDate())
AND A.DateOfEntry >= (Select DateOfEntry FROM TableA AS D where D.ESource = 'Detail')
AND A.UnitPrice = (Select UnitPrice FROM TableA AS E where E.ESource = 'Detail')
ORDER BY IH.DateOfEntry DESC
Tables are:
Table A:
Policy Fund Units Price ESource Date
120 BR 6 0.74 RE 2015
120 BR -100 0.72 Detail 2014
120 BR 6 0.71 RE 2013
TABLE C:
Policy Fund TotalUnits
120 BR 400
DESIRED RESULT:
Policy Fund Sum Price Value
120 BR [6+(-100)] = -94 0.72 [(400+(-94))*0.72] = 220.32
As well as the sub query issues - the command to get price = 0.72 [where ="Detail"] is stopping the sum of both rows occurring making Sum = -100 and not -94
Any help with the errors would be greatly appreciated
The problem is in your where clause:
where A.PolicyNumber = '120' AND
C.NumberOfUnits > 0 AND
C.InvestmentFund = A.InvestmentFund AND
A.DateOfEntry < DATEADD(year, -1, GetDate()) AND
A.DateOfEntry >= (Select DateOfEntry FROM TableA AS D where D.ESource = 'Detail') AND
A.UnitPrice = (Select UnitPrice FROM TableA AS E where E.ESource = 'Detail')
The last two clauses are the problem. One way to fix this is with the keywords ANY, SOME, or ALL:
where A.PolicyNumber = '120' AND
C.NumberOfUnits > 0 AND
C.InvestmentFund = A.InvestmentFund AND
A.DateOfEntry < DATEADD(year, -1, GetDate()) AND
A.DateOfEntry >= ALL (Select DateOfEntry FROM TableA AS D where D.ESource = 'Detail') AND
A.UnitPrice = ALL (Select UnitPrice FROM TableA AS E where E.ESource = 'Detail')
However, I prefer explicit aggregation:
where A.PolicyNumber = '120' AND
C.NumberOfUnits > 0 AND
C.InvestmentFund = A.InvestmentFund AND
A.DateOfEntry < DATEADD(year, -1, GetDate()) AND
A.DateOfEntry >= (Select MAX(DateOfEntry) FROM TableA AS D where D.ESource = 'Detail') AND
A.UnitPrice = (Select MAX(UnitPrice) FROM TableA AS E where E.ESource = 'Detail')
Note that the query in your question seems to be missing a from clause. And the condition C.InvestmentFund = A.InvestmentFun should be in an on clause not in the where clause.

most recent entry made in table bases on one year interval mysql

Using the following sqlfiddle here How would I find the most recent payment made between the months of 2012-04-1 and 2012-03-31 using the case statement as in the previous queries
I tried this:
max(case when py.pay_date >= STR_TO_DATE(CONCAT(2012, '-04-01'),'%Y-%m-%d') and py.pay_date <= STR_TO_DATE(CONCAT(2012, '-03-31'), '%Y-%m-%d') + interval 1 year then py.amount end) CURRENT_PAY
However the answer I am getting is incorrect, where the actual answer should be:(12, '2012-12-12', 20, 1)
Please Provide me with some assistance, thank you.
Rather than a CASE inside your MAX() aggregate, that condition belongs in the WHERE clause. This joins against a subquery which pulls the most recent payment per person_id by joining on MAX(pay_date), person_id.
SELECT payment.*
FROM
payment
JOIN (
SELECT MAX(pay_date) AS pay_date, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id
) maxp ON payment.person_id = maxp.person_id AND payment.pay_date = maxp.pay_date
Here is an updated fiddle with the ids corrected in your table (since a bunch of them were 15). This returns record 18, for 2013-03-28.
Update
After seeing the correct SQL fiddle... To incorporate the results of this query into your existing one, you can LEFT JOIN against it as a subquery on p.id.
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then py.amount end) april_amount,
(case when max(py.pay_date)and month(py.pay_date)= 4 then py.amount else 0 end) max_pay_april,
sum(case
when Month(py.pay_date) = Month(curdate())
then py.amount end) current_month_amount,
sum(case
when Month(py.pay_date) = Month(curdate())-1
then py.amount end) previous_month_amount,
maxp.pay_date AS last_pay_date,
maxp.amount AS last_pay_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
/* LEFT JOIN against the subquery: */
left join (
SELECT MAX(pay_date) AS pay_date, amount, person_id
FROM payment
WHERE pay_date BETWEEN '2012-04-01' AND DATE_ADD('2012-03-31', INTERVAL 1 YEAR)
GROUP BY person_id, amount
) maxp ON maxp.person_id = p.id
group by p.name,
v.v_name