Convert mysql to doctrine - mysql

I have the following MySQL query
select a.*, d.*, p.*, pow.* from appointment a
left join doctor d on d.id = a.doctor_id
left join patient p on p.id = a.patient_id
left join point_of_work pow on pow.id = a.point_of_work_id
where (doctor_id, patient_id, date) = (
select doctor_id, patient_id,
coalesce(
min(case when date > curdate() then date end),
max(case when date < curdate() then date end)
) date
from appointment
where (doctor_id, patient_id) = (a.doctor_id, a.patient_id)
)
and d.external_id = 1
And I am trying to convert it to DQL.
Right now I come to this version of DQL but it seems I'am doing something (or maybe more things:( wrong)
$expr = $this->getEntityManager()->getExpressionBuilder();
$queryBuilder = $this->createQueryBuilder('a')
->leftJoin(Doctor::class, 'd')
->leftJoin(Patient::class, 'p')
->leftJoin(PointOfWork::class, 'pow')
->where(
$expr->eq('doctorId, patient_id, date',
$this->createQueryBuilder('a')
->select(Appointment::class . ',
coalesce(
min(case when date > curdate() then date end),
max(case when date < curdate() then date end)
) date'
)
->where ('(doctorId, patientId) = (a.doctorId, a.patientId)')
)
)
->andWhere('d.externalId = :externalId')
->setParameter('externalId', $doctorExternalId)
->setMaxResults($limit)
->setFirstResult($offset);
What approaches do I need for the DQL conversion?

Related

Convert mysql query to sqlite

I am new to sqlite3.I am currently using mysql. But I will be migrating it to sqlite3.
I am calculating month end balance
SELECT c.country,
Date_format(Last_day(Str_to_date(dt.date, '%m/%d/%Y')), '%Y/%m/%d')
AS Month_End_Balance,
Sum(dt.amount) AS in_Euro
FROM deposit_transactions AS dt
LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country,
Month_End_Balance
order by Month_End_Balance desc
Need help in converting it to sqlite
Question
Need help in Last_Day function alternative in sqlite
Refer below query for SQLITE -
Please make adjustment as per needed date format.
with new_dep_trx as (
select deposit_id,customer_id,
transaction_type,amount,currency,
case when (length(dt.date)=8 or length(dt.date)=9) and instr(substr(dt.date,1,2),'/')>0
then
date(substr(dt.date,length(dt.date)-3,4)||'-0'||substr(dt.date,1,1)||'-0'||substr(dt.date,3,1))
when length(dt.date)=9 and instr(substr(dt.date,1,2),'/')=0
then
date(substr(dt.date,length(dt.date)-3,4)||'-'||substr(dt.date,1,2)||'-0'||substr(dt.date,4,1))
else
date(substr(dt.date,length(dt.date)-3,4)||'-'||substr(dt.date,1,2)||'-'||substr(dt.date,4,2)) end date_col
from deposit_transactions dt
)
select
c.country,
strftime('%Y-%m',dt.date_col) as month,
strftime('%m/%d/%Y',date(dt.date_col,'start of month','+1 month','-1 day')) as last_day_of_month,
strftime('%Y/%m/%d',date(dt.date_col,'start of month','+1 month','-1 day')) as last_day_of_month_your_format,
SUM(
dt.amount *
(CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END) *
(CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END)
) amount_eur
FROM new_dep_trx dt
LEFT JOIN customers c ON c.customer_id = dt.customer_id
GROUP BY c.country, last_day_of_month_your_format;
Modified DB fiddle.
First, you must update the column date of the table deposit_transactions so that it has the format YYYY-mm-dd the only text date format that you can use with SQLite's datetime functions:
UPDATE deposit_transactions
SET date = SUBSTR(date, -4) || '-' ||
printf('%02d', date + 0) || '-' ||
printf('%02d', SUBSTR(date, INSTR(date, '/') + 1, 2) + 0);
Now, you can use the function date() to get the last day of each month with:
date(date, 'start of month', '+1 month', '-1 day')
So, your query should be:
SELECT c.country,
date(dt.date, 'start of month', '+1 month', '-1 day') AS Month_End_Balance,
SUM(dt.amount *
CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END *
CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END
) AS amount_eur
FROM deposit_transactions AS dt LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country, Month_End_Balance
ORDER BY Month_End_Balance DESC;
If you want to format the dates of the resultset to mm/dd/YYYY and sort properly by the date and not the formatted date which would sort incorrectly:
SELECT c.country,
strftime('%m/%d/%Y', date(dt.date, 'start of month', '+1 month', '-1 day')) AS Month_End_Balance,
SUM(dt.amount *
CASE WHEN dt.currency = 'GBP' THEN .85 ELSE 1 END *
CASE WHEN dt.transaction_type = 'pay_in' THEN 1 ELSE -1 END
) AS amount_eur
FROM deposit_transactions AS dt LEFT JOIN customers AS c
ON c.customer_id = dt.customer_id
GROUP BY c.country, date(dt.date, 'start of month', '+1 month', '-1 day')
ORDER BY date(dt.date, 'start of month', '+1 month', '-1 day') DESC;
See the demo.

Case When Exists In Subquery

I am trying to check whether an ID is present in a subquery. I have ran just the subquery and it produces a list of all the ID's which have a fee against it, so what I want to do is check whether the ID in the main query is present in the subquery. If it's present then return 1, else return 0.
This is an easy query but I have no idea where i'm going wrong, I tried using exists rather than in but this does not work either.
case when debtor._rowid in (
select distinct note.debtorid from note
left join debtor on note.debtorid = debtor._rowid
left join fee on fee.debtorid = debtor._rowid
where fee.type = "Enforcement" and note.type = "Stage")
then 1 else 0 end) as `Enforcement`
Below is the entire code, when I remove the above code from the main query below, it works perfectly, so there's something wrong in my case statement.
with cte_1
as
(
select
debtor._rowid as casref
,concat(date_format(date_sub(debtor._createddate, interval 3 month), '%y'), '/', date_format(date_add(debtor._createddate, interval 9 month), '%y')) as `F/Y`
,date_format(debtor._createddate, '%M %Y') as `Loaded Month`
,ifnull(concat(date_format(date_sub(debtor.offence_date, interval 3 month), '%y'), '/', date_format(date_add(debtor.offence_date, interval 9 month), '%y')),'-') as `LO F/Y`
,coalesce(date_format(debtor.offence_date,'%M %Y'),'-') as `Liability Order Month`
,scheme.name as `Scheme`
,branch.name as `Branch`
,count(debtor._rowid) as `Cases Received`
,count(debtor.linkid) as `LinkID`
,(case
when concat(date_format(date_sub(debtor._createddate, interval 3 month), '%y'), '/', date_format(date_add(debtor._createddate, interval 9 month), '%y'))
= ifnull(concat(date_format(date_sub(debtor.offence_date, interval 3 month), '%y'), '/', date_format(date_add(debtor.offence_date, interval 9 month), '%y')),'-')
then 1 else 0 end ) as `Same Year`
, case when debtor._rowid in (
select distinct note.debtorid from note
left join debtor on note.debtorid = debtor._rowid
left join fee on fee.debtorid = debtor._rowid
where fee.type = "Enforcement"
and note.type = "Stage")
then 1 else 0 end) as `Enforcement`
from debtor
left join clientscheme on debtor.clientschemeID = clientscheme._rowid
left join scheme on clientscheme.schemeID = scheme._rowid
left join branch on clientscheme.branchID = branch._rowid
left join fee on debtor._rowid = fee.debtorid
left join note on debtor._rowid = note.debtorid
where clientscheme.branchID in (1,10,24)
and debtor._createddate >= '2017-04-01'
group by debtor._rowid
)
,
cte_2
as
(
select
`F/Y`
,`Loaded Month`
,`LO F/Y`
,`Liability Order Month`
,`Scheme`
,`Branch`
,sum(`Cases Received`) as `Case Count`
,sum(`LinkID`) as `Linked Accounts`
,sum(`Same Year`) as `In Year LO`
,sum(Enforcement) as `Enforcement Applied`
from cte_1
group by
`Loaded Month`
,`Liability Order Month`
,`Scheme`
, `Branch`
)
select
`F/Y`
,`Loaded Month`
,`LO F/Y`
,`Liability Order Month`
,`Scheme`
,`Branch`
,`Case Count`
,`Linked Accounts`
,round((`Linked Accounts`/`Case Count`),2) * 100 as `% of Linked Accounts`
,round((`In Year LO`/`Case Count`),2) * 100 as `In Year LO's`
,`Enforcement Applied`
from cte_2
It appears that you want to logically check if, for a given record in the result set, a _noteid value from the debtor table matches to a debtors from the note table. You could rephrase your query as follows:
SELECT
(d._rowid = n.debtorid) AS `Enforcement Allocated`
FROM note n
LEFT JOIN debtor d
ON n.debtorid = d._rowid
LEFT JOIN fee f
ON f.debtorid = d._rowid
WHERE
f.type = 'Enforcement' AND n.type = 'Stage';
Note that since the output of your CASE expression is just 1 or 0, you may take advantage of that MySQL allows boolean expressions as values.

Total the aggregate in Select Case Statement

Is there a way to get a total from the aggregate in each select case statement? The following gives me the correct total by listing the total for each month in a column but I would like to have a single total for each case statement.
SELECT SUM(
CASE WHEN dbo.bill_t_ARTransaction.TransactionDate BETWEEN '2000-01-01' AND '2016-12-31' THEN dbo.bill_t_ARTransaction.Amount ELSE 0 END
) AS 'Dec16'
, SUM(
CASE WHEN dbo.bill_t_ARTransaction.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31' THEN dbo.bill_t_ARTransaction.Amount ELSE 0 END
) AS 'JAN17'
FROM dbo.bill_t_ARTransaction
INNER JOIN dbo.bill_t_TripTicket ON (
dbo.bill_t_ARTransaction.RunNumber = dbo.bill_t_TripTicket.RunNumber
)
INNER JOIN dbo.med_m_Company ON (
dbo.bill_t_TripTicket.CompanyCode = dbo.med_m_Company.CompanyCode
)
WHERE dbo.bill_t_TripTicket.CompanyCode = '105'
AND dbo.bill_t_ARTransaction.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31'
GROUP BY dbo.bill_t_ARTransaction.TransactionDate
I just formated your SQL - so it will be more readable for human beings - and put it in a Subselect.
In the outer Select i just added the SUM of the two calculated columns
SELECT sums.*
,SUM(sums.DEC16 + sums.JAN17) AS TOTAL_SUM
FROM (
SELECT SUM( CASE WHEN dbo.bill_t_ARTransaction.TransactionDate
BETWEEN '2000-01-01'
AND '2016-12-31'
THEN dbo.bill_t_ARTransaction.Amount
ELSE 0
END
) AS DEC16
,SUM( CASE WHEN dbo.bill_t_ARTransaction.TransactionDate
BETWEEN '2000-01-01'
AND '2017-01-31'
THEN dbo.bill_t_ARTransaction.Amount
ELSE 0
END
) AS JAN17
FROM dbo.bill_t_ARTransaction
INNER JOIN dbo.bill_t_TripTicket
ON dbo.bill_t_ARTransaction.RunNumber = dbo.bill_t_TripTicket.RunNumber
INNER JOIN dbo.med_m_Company
ON dbo.bill_t_TripTicket.CompanyCode = dbo.med_m_Company.CompanyCode
WHERE dbo.bill_t_TripTicket.CompanyCode = '105'
AND dbo.bill_t_ARTransaction.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31'
GROUP BY dbo.bill_t_ARTransaction.TransactionDate
) sums
I think you just want to get right of the GROUP BY:
SELECT SUM(CASE WHEN ba.TransactionDate BETWEEN '2000-01-01' AND '2016-12-31'
THEN ba.Amount ELSE 0
END) AS Dec16,
SUM(CASE WHEN ba.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31'
THEN ba.Amount ELSE 0
END) AS JAN17
FROM dbo.bill_t_ARTransaction ba INNER JOIN
dbo.bill_t_TripTicket bt
ON ba.RunNumber = bt.RunNumber INNER JOIN
dbo.med_m_Company c
ON bt.CompanyCode = c.CompanyCode
WHERE bt.CompanyCode = '105' AND
ba.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31';
Note the other changes I made to the query:
I removed the single quotes from the column aliases. Single quotes should only be used for string and date values (using them for column aliases is allowed but can cause confusion).
The tables are given aliases.
The column names are qualified with the aliases (the query is easier to write and to read.
Note that '105' should not have quotes, if CompanyCode is numeric.
I think the query can be simplified to:
SELECT SUM(CASE WHEN ba.TransactionDate BETWEEN '2000-01-01' AND '2016-12-31'
THEN ba.Amount ELSE 0
END) AS Dec16,
SUM(CASE WHEN ba.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31'
THEN ba.Amount ELSE 0
END) AS JAN17
FROM dbo.bill_t_ARTransaction ba INNER JOIN
dbo.bill_t_TripTicket bt
ON ba.RunNumber = bt.RunNumber
WHERE bt.CompanyCode = 105 AND
ba.TransactionDate BETWEEN '2000-01-01' AND '2017-01-31';
The Company table does not appear to be being used.
You can do this:
SELECT DATENAME(MONTH, Transaction.TransactionDate) + RIGHT(YEAR(Transaction.TransactionDate), 2) AS MonthYear
, SUM(Transaction.Amount) AS Amount
FROM dbo.bill_t_ARTransaction Transaction
INNER JOIN dbo.bill_t_TripTicket Ticket
ON Transaction.RunNumber = Ticket.RunNumber
INNER JOIN dbo.med_m_Company Company
ON Ticket.CompanyCode = Company.CompanyCode
WHERE Ticket.CompanyCode = '105'
AND Transaction.TransactionDate >= '2000-01-01'
AND Transaction.TransactionDate < '2017-02-01'
GROUP BY DATENAME(MONTH, Transaction.TransactionDate) + RIGHT(YEAR(Transaction.TransactionDate), 2)
Assuming dbo.bill_t_ARTransaction.TransactionDate is a datetime(2): Are you aware that in 'DEC16' you are missing transaction from (as an example) 2016-12-31 11:00:00? BETWEEN is inclusive on both sides, and dates are defaulted to midnight (00:00:00) if no time component is defined. I altered the WHERE clause accordingly. I also added aliases to help the readability.

How to perform multiple calculations with in a single query

I have a situation where in i have to get the data from an Year Ago , Previous Month and Current Month. What is the best way to achieve this ?
I have a table which contains the year,month and data in it. In the below query have added a filter
c.ReportMonth = DATENAME(month, #12MonthsAgo) and c.ReportYear = Year(#12MonthsAgo)
This is for an year ago. In the same way if i have to get the previous month and current month, can i do that with in the same query by setting the filters ? how do we do that ?
Is there a better way other than i end up writing 3 select queries and then putting the select to a tmp table and later merging the tables ?
create table #TPTABLE
(
KPIName varchar(150)
,MetricName Varchar(200)
,MetricId INT
,DataSource varchar(50)
,[AnYearAgo] Float
,[PreviousMonth] float
,[CurrentMonth] float
);
insert into #TPTABLE
(KPIName,MetricName,MetricId,DataSource,[AnYearAgo])
SELECT
p.KPIName
,p.MetricName
,p.MetricId
,p.DataSource
,c.Value as [AnYearAgo]
FROM [IntegratedCare].[report].[KPIMetricDetails] p
LEFT JOIN [IntegratedCare].[report].[KPIMectricValues] c
ON p.[MetricId] = c.MetricId
WHERE c.ReportMonth = DATENAME(month, #12MonthsAgo) and c.ReportYear = Year(#12MonthsAgo)
ORDER BY KPI_Id ASC, [MetricId] ASC
SELECT
p.KPIName
,p.MetricName
,p.MetricId
,p.DataSource
,c.Value
,c2.Value
,c3.Value
FROM [IntegratedCare].[report].[KPIMetricDetails] p
LEFT JOIN [IntegratedCare].[report].[KPIMectricValues] c
ON p.[MetricId] = c.MetricId
AND c.[CommissionerCode] = COALESCE(NULLIF(#Commissioner, ''), c.[CommissionerCode])
ANd ReportMonth = DATENAME(month, #12MonthsAgo) and c.ReportYear = Year(#12MonthsAgo)
LEFT JOIN [IntegratedCare].[report].[KPIMectricValues] c2
ON p.[MetricId] = c2.MetricId
AND c2.[CommissionerCode] = COALESCE(NULLIF(#Commissioner, ''), c2.[CommissionerCode])
ANd c2.ReportMonth = DATENAME(month, #PreviousMonth) and c2.ReportYear = Year(#PreviousMonth)
LEFT JOIN [IntegratedCare].[report].[KPIMectricValues] c3
ON p.[MetricId] = c3.MetricId
AND c3.[CommissionerCode] = COALESCE(NULLIF(#Commissioner, ''), c3.[CommissionerCode])
ANd c3.ReportMonth = DATENAME(month, #PreviousMonth) and c3.ReportYear = Year(#PreviousMonth)
ORDER BY p.KPI_Id ASC, p.[MetricId] ASC
I think what you need is this:
insert into #TPTABLE
(KPIName,MetricName,MetricId,DataSource,[AnYearAgo])
SELECT
KPIName
,MetricName
,MetricId
,DataSource
,[AnYearAgo]
,[PreviousMonth]
,[CurrentMonth]
FROM (
SELECT
KPIName
,MetricName
,MetricId
,DataSource
,KPI_Id
,sum(case when c.ReportMonth = DATENAME(month, #12MonthsAgo) and c.ReportYear = Year(#12MonthsAgo) then c.Value else 0 end) as [AnYearAgo]
,sum(case when c.ReportMonth = DATENAME(month, #PreviousMonth) and c.ReportYear = Year(#PreviousMonth) then c.Value else 0 end) as [PreviousMonth]
,sum(case when c.ReportMonth = DATENAME(month, #CurrentMonth) and c.ReportYear = Year(#CurrentMonth) then c.Value else 0 end) as [CurrentMonth]
FROM [IntegratedCare].[report].[KPIMetricDetails] p
LEFT JOIN [IntegratedCare].[report].[KPIMectricValues] c
ON p.[MetricId] = c.MetricId
GROUP BY KPIName, MetricName, MetricId, DataSource, KPI_Id
ORDER BY KPI_Id ASC, [MetricId] ASC

MySQL "Trending"

I'm selecting "ideas" from my database currently, but another requirement is to be able to grab "trending ideas", that is, the top 10 most-up-voted ideas within the last 7 days.
My query for selecting "ideas" is this:
SELECT
t.id AS 'id',
CONCAT(t.first_name, ' ', SUBSTRING(t.last_name,1,1)) AS 'name',
t.votes_up,
t.votes_down,
t.votes_aggregate,
GROUP_CONCAT(DISTINCT tags.name) AS 'tags',
t.createdon AS 'timestamp'
FROM (
SELECT
ideas.id, first_name, last_name, createdon,
COALESCE(SUM(case when value > 0 then value end),0) votes_up,
COALESCE(SUM(case when value < 0 then value end),0) votes_down,
COALESCE(SUM(value),0) votes_aggregate
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
GROUP BY ideas.id
) as t
LEFT JOIN tags_rel ON t.id = tags_rel.idea_id
LEFT JOIN tags ON tags_rel.tag_id = tags.id
How would I get and display all the votes, but only get the "ideas" that have been voted up (votes_up) within the last 7 days and ordered by the amount of votes_up ?
This is my attempt:
SELECT
t.id AS 'id',
CONCAT(t.first_name, ' ', SUBSTRING(t.last_name,1,1)) AS 'name',
t.votes_up,
t.votes_down,
t.votes_aggregate,
GROUP_CONCAT(DISTINCT tags.name) AS 'tags',
t.createdon AS 'timestamp'
FROM (
SELECT
ideas.id, first_name, last_name, createdon,
COALESCE(SUM(case when value > 0 then value end),0) votes_up,
COALESCE(SUM(case when value < 0 then value end),0) votes_down,
COALESCE(SUM(value),0) votes_aggregate
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
GROUP BY ideas.id
) as t
LEFT JOIN tags_rel ON t.id = tags_rel.idea_id
LEFT JOIN tags ON tags_rel.tag_id = tags.id
WHERE t.published = 1
AND (
SELECT ideas.id,
COALESCE(SUM(case when value > 0 then value end),0) votes_up
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
WHERE votes.`timestamp` > (NOW() - INTERVAL 7 DAY)
GROUP BY ideas.id
) as v
GROUP BY t.id
ORDER BY v.votes_up DESC
But I get the error for the right syntax to use near 'as v GROUP BY t.id ORDER BY v.votes_up DESC LIMIT 10'
You're using the 'AS v' in a WHERE clause, which isn't possible:
WHERE t.published = 1
AND (
SELECT ideas.id,
COALESCE(SUM(case when value > 0 then value end),0) votes_up
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
WHERE votes.`timestamp` > (NOW() - INTERVAL 7 DAY)
GROUP BY ideas.id
) as v
Try this one, in your SELECT statement you do the subquery, in your WHERE you check if this isn't NULL and you can order by it (if i'm right):
SELECT
t.id AS 'id',
CONCAT(t.first_name, ' ', SUBSTRING(t.last_name,1,1)) AS 'name',
t.votes_up,
t.votes_down,
t.votes_aggregate,
GROUP_CONCAT(DISTINCT tags.name) AS 'tags',
t.createdon AS 'timestamp',
(
SELECT ideas.id,
COALESCE(SUM(case when value > 0 then value end),0) votes_up
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
WHERE votes.`timestamp` > (NOW() - INTERVAL 7 DAY)
GROUP BY ideas.id
) AS vup
FROM (
SELECT
ideas.id, first_name, last_name, createdon,
COALESCE(SUM(case when value > 0 then value end),0) votes_up,
COALESCE(SUM(case when value < 0 then value end),0) votes_down,
COALESCE(SUM(value),0) votes_aggregate
FROM ideas
LEFT JOIN votes ON ideas.id = votes.idea_id
GROUP BY ideas.id
) as t
LEFT JOIN tags_rel ON t.id = tags_rel.idea_id
LEFT JOIN tags ON tags_rel.tag_id = tags.id
WHERE t.published = 1
AND vup IS NOT NULL
GROUP BY t.id
ORDER BY vup DESC