Convert query select to a cursor - sql

I need to convert my SQL Server query in a cursor.
I tried with the example of question Select statement in cursor but I had error.
Here my query:
SELECT DISTINCT
U.IDSocio, U.IDUtente,
U.Cognome, U.Nome, U.Sesso,
U.Luogo_Nascita,
U.Provincia_Nascita,
U.Stato_Nascita,
COALESCE(C.codice, SS.codice) as Nascita_CodCatastale,
CONVERT(DATE, U.Data_Nascita) AS Data_Nascita_Orig,
REPLACE(CONVERT(VARCHAR, U.Data_Nascita, 111), '/', '-') as Data_Nascita,
U.Indirizzo_Via as Residenza_Indirizzo,
U.Indirizzo_NumeroCivico as Residenza_NumeroCivico,
U.Indirizzo_Cap as Residenza_Cap,
U.Indirizzo_Citta as Residenza_Citta,
U.Indirizzo_Pv as Residenza_Provincia,
U.CodCatastaleResidenza as Residenza_CodCatastale,
U.Indirizzo_Stato as Residenza_Stato,
U.PIVA,
U.CodiceFiscale,
U.Documento,
U.Telefono_1,
U.Telefono_2,
U.SMS,
U.Email,
U.Note,
UG.Descrizione as Categoria,
U.AutorizzaSMS,
U.AutorizzaEmail,
U.AutorizzaCartaceo,
U.CFRicevuta,
U.CFRicevutaUtente
FROM [dbo].[Utenti] U
LEFT JOIN dbo.UtenteCustom UC on UC.IDUtente = U.IDUtente
LEFT JOIN dbo.UtentiCategorie UG on UG.IDCategoria = UC.IDCategoriaUtente
LEFT JOIN dbo.Comuni C on C.Comune = U.Luogo_Nascita and C.PV = U.Provincia_Nascita
LEFT JOIN dbo.Comuni SS on SS.Comune = U.Stato_Nascita
INNER JOIN dbo.AbbonamentiIscrizione AI ON U.IDUtente = AI.IDUtente
INNER JOIN dbo.AbbonamentiDurata AD ON AI.IDDurata = AD.IDDurata
INNER JOIN dbo.Abbonamenti A ON A.IDAbbonamento = AD.IDAbbonamento
INNER JOIN dbo.AziendeAbbonamenti AA On AA.IDAbbonamentoCategoria = A.IDCategoria
INNER JOIN dbo.TesseramentiAbbonamentiDurata TAD On TAD.IDDurata = AD.IDDurata
WHERE
COALESCE(AA.IDRicevutaAzienda, 2) = 2
AND (U.Cognome <> '' AND U.Nome <> '')
AND CONVERT(DATE, DataInizio) <= CONVERT(DATE, GETDATE())
AND CONVERT(DATE, DataFine) >= CONVERT(DATE, GETDATE())
ORDER BY U.IDUtente
Could you please help me to convert it into a cursor? I need to use a cursor because the query has many rows as result and the code that use it is too slow to execute.

Related

incorrect syntax near the keyword where for using subquery

SELECT DISTINCT dbo.master_order.order_no,
dbo.master_order.program_no,
dbo.Setup_size.size_name,
dbo.Setup_color.color_name,
dbo.Setup_color.color_no,
dbo.transaction_production.total_weight,
dbo.Setup_yarn.yarn_count,
dbo.Setup_article_order.article_name,
dbo.master_order.shipment_date,
#from AS reprt,
#to AS reprt1,
dbo.transaction_order.quantity,
dbo.transaction_order.gsm
FROM dbo.master_order
INNER JOIN dbo.transaction_order ON dbo.master_order.order_id = dbo.transaction_order.order_id
INNER JOIN dbo.transaction_production ON dbo.transaction_order.trans_id = dbo.transaction_production.trans_id
INNER JOIN dbo.Setup_size ON dbo.transaction_order.size_id = dbo.Setup_size.size_id
INNER JOIN dbo.Setup_yarn ON dbo.transaction_order.yarn_id = dbo.Setup_yarn.yarn_id
INNER JOIN dbo.Setup_article_order ON dbo.transaction_order.article_id = dbo.Setup_article_order.article_id
INNER JOIN dbo.Setup_color ON dbo.transaction_order.color_id = dbo.Setup_color.color_id
AND dbo.Setup_yarn.color_id = dbo.Setup_color.color_id
WHERE dbo.setup_color.color_id=
(SELECT color_no
FROM dbo.setup_color) WHERE master_order.shipment_date>=#from
AND master_order.shipment_date<=#to
This is your syntax after WHERE clause
where dbo.setup_color.color_id=
(select color_no from dbo.setup_color)
where master_order.shipment_date>=
#from and master_order.shipment_date<=#to
there are 2 Where clauses used on main Query.
use in instead of equals for a subquery.
SELECT DISTINCT
dbo.master_order.order_no,
dbo.master_order.program_no,
dbo.Setup_size.size_name,
dbo.Setup_color.color_name,
dbo.Setup_color.color_no,
dbo.transaction_production.total_weight,
dbo.Setup_yarn.yarn_count,
dbo.Setup_article_order.article_name,
dbo.master_order.shipment_date,
#from as reprt,
#to as reprt1,
dbo.transaction_order.quantity,
dbo.transaction_order.gsm
FROM dbo.master_order
INNER JOIN dbo.transaction_order ON dbo.master_order.order_id = dbo.transaction_order.order_id
INNER JOIN dbo.transaction_production ON dbo.transaction_order.trans_id = dbo.transaction_production.trans_id
INNER JOIN dbo.Setup_size ON dbo.transaction_order.size_id = dbo.Setup_size.size_id
INNER JOIN dbo.Setup_yarn ON dbo.transaction_order.yarn_id = dbo.Setup_yarn.yarn_id
INNER JOIN dbo.Setup_article_order ON dbo.transaction_order.article_id = dbo.Setup_article_order.article_id
INNER JOIN dbo.Setup_color ON dbo.transaction_order.color_id = dbo.Setup_color.color_id
AND dbo.Setup_yarn.color_id = dbo.Setup_color.color_id where dbo.setup_color.color_id in
(select color_no from dbo.setup_color) where master_order.shipment_date >= #from and master_order.shipment_date<= #to
The problem is that you have 2 WHERE clauses in the main query. as master_order is a table used in main query, just replace 2nd WHERE withAND as below.
SELECT DISTINCT dbo.master_order.order_no,
dbo.master_order.program_no,
dbo.Setup_size.size_name,
dbo.Setup_color.color_name,
dbo.Setup_color.color_no,
dbo.transaction_production.total_weight,
dbo.Setup_yarn.yarn_count,
dbo.Setup_article_order.article_name,
dbo.master_order.shipment_date,
#from AS reprt,
#to AS reprt1,
dbo.transaction_order.quantity,
dbo.transaction_order.gsm
FROM dbo.master_order
INNER JOIN dbo.transaction_order ON dbo.master_order.order_id = dbo.transaction_order.order_id
INNER JOIN dbo.transaction_production ON dbo.transaction_order.trans_id = dbo.transaction_production.trans_id
INNER JOIN dbo.Setup_size ON dbo.transaction_order.size_id = dbo.Setup_size.size_id
INNER JOIN dbo.Setup_yarn ON dbo.transaction_order.yarn_id = dbo.Setup_yarn.yarn_id
INNER JOIN dbo.Setup_article_order ON dbo.transaction_order.article_id = dbo.Setup_article_order.article_id
INNER JOIN dbo.Setup_color ON dbo.transaction_order.color_id = dbo.Setup_color.color_id
AND dbo.Setup_yarn.color_id = dbo.Setup_color.color_id
WHERE dbo.setup_color.color_id=
(SELECT color_no
FROM dbo.setup_color)
AND master_order.shipment_date>=#from
AND master_order.shipment_date<=#to
Also if the table dbo.setup_color has more than 1 value, either use IN instead of = or add a WHERE clause to the inner query to return just one value, otherwise it will throw error.

Returning the sum of a select statement SQL

I have created a SELECT statement:
SELECT ARII2.Amount
FROM
AR_Customer ARC2
Inner JOIN AR_Customer_Site ARCS2 On ARC2.Customer_Id = ARCS2.Customer_Id AND ARCS2.Customer_Id = ARC2.Customer_Id
INNER JOIN AR_Customer_System ARCSYS2 On ARCS2.Customer_Site_Id = ARCSYS2.Customer_Site_Id
INNER JOIN AR_Branch ARB2 ON ARB2.Branch_Id = ARC2.Branch_Id
INNER JOIN AR_Invoice ARIN2 ON ARIN2.Customer_Site_Id = ARCS2.Customer_Site_Id
INNER JOIN AR_Invoice_Item ARII2 ON ARII2.Invoice_Id = ARIN2.Invoice_Id
Inner JOIN SY_System SYSY2 On ARCSYS2.System_Id = SYSY2.System_Id
WHERE
ARIN2.Invoice_Date > dateadd(year, -1, getdate())
AND ARC2.Customer_Number = '300000'
AND ARII2.[Description] LIKE ('Warranty Credit')
OR ARII2.[Description] = ('Warranty Credit T')
GROUP BY ARII2.Amount
that returns the following results.
2031.00
1458.98
1272.50
620.00
160.00
My thought was that I could put a SUM around my Amount and it would return the desired value of 5542.48 (the total of the values).
SELECT
SUM(ARII2.Amount)
FROM
AR_Customer ARC2
Inner JOIN AR_Customer_Site ARCS2 On ARC2.Customer_Id = ARCS2.Customer_Id AND ARCS2.Customer_Id = ARC2.Customer_Id
INNER JOIN AR_Customer_System ARCSYS2 On ARCS2.Customer_Site_Id = ARCSYS2.Customer_Site_Id
INNER JOIN AR_Branch ARB2 ON ARB2.Branch_Id = ARC2.Branch_Id
INNER JOIN AR_Invoice ARIN2 ON ARIN2.Customer_Site_Id = ARCS2.Customer_Site_Id
INNER JOIN AR_Invoice_Item ARII2 ON ARII2.Invoice_Id = ARIN2.Invoice_Id
Inner JOIN SY_System SYSY2 On ARCSYS2.System_Id = SYSY2.System_Id
WHERE
ARIN2.Invoice_Date > dateadd(year, -1, getdate())
AND ARC2.Customer_Number = '300000'
--AND ARIN2.Invoice_Number = '204686'
AND ARII2.[Description] LIKE ('Warranty Credit')
OR ARII2.[Description] = ('Warranty Credit T')
GROUP BY ARII2.Amount, ARII2.[Description]
Which returned the following results which are not what I am looking for.
-10155.00
-7294.90
-6362.50
-3100.00
-800.00
As always any help on this is GREATLY appreciated!
You are getting multiple rows because of your GROUP BY. Remove that line, and you will only get the one total SUM.

Why does the query that creates the view run faster than Select 1000 from same view

I have built a query that I have turned into a view, the query within the view runs in about 9 minutes with a row count of 1.6 million. When I query Select Top 1000 from that view it runs continuously without supplying any results. Why would something like this happen?
CREATE VIEW [dbo].[v_BP_OP]
AS
--pulls ORCA BPs
with OBP as (
SELECT DISTINCT s.EPI
,e.CONTACT_DATE
,s.EventDtTm
,s.SBP
,d.dbp
FROM uwEpicClarity.dbo.PAT_ENC e
with(nolock)
INNER JOIN [uwQAQI_DS].[dbo].[v_BP_Systolic]s
with(nolock)on e.EPI = s.EPI and CONVERT(date,e.CONTACT_DATE) = CONVERT(date,s.EventDtTm)
INNER JOIN [uwQAQI_DS].[dbo].[v_BP_Diastolic]d
with(nolock)on s.EID = d.EID and s.EventDtTm = d.EventDtTm
WHERE e.CONTACT_DATE >= '2014-01-01'
and e.ENC_TYPE_C in (50,101)
and e.APPT_STATUS_C_DESCR in ('Completed','Arrived')
and s.Src = 'ORCA_CE'
and d.Src = 'ORCA_CE'
)
--combines ORCA and Epic BPS
SELECT DISTINCT EPI
,CONTACT_DATE
,EventDtTm
,CAST(SBP as varchar) + '/' + CAST(DBP as varchar) as Meas_Value
,'ORCA' as SrcSys
FROM obp
UNION
SELECT DISTINCT e.EPI
,e.CONTACT_DATE
,fm.[RECORDED_TIME]
,CAST(MEAS_VALUE as varchar)as MEAS_VALUE
,'Epic' as SrcSys
FROM [uwEpicClarity].[dbo].[IP_FLWSHT_MEAS] fm with (NoLock)
INNER JOIN uwEpicClarity.dbo.[IP_FLWSHT_REC] fr with (NoLock) on fm.FSD_ID = fr.FSD_ID
INNER JOIN uwEpicClarity.dbo.PAT_ENC e with (NoLock) on fr.INPATIENT_DATA_ID = e.INPATIENT_DATA_ID
WHERE e.CONTACT_DATE >= '2014-01-01'
and FLO_MEAS_ID in ('5','116')
and e.ENC_TYPE_C in (50,101)
and e.APPT_STATUS_C_DESCR in ('Completed','Arrived')
GO

Query Performance too Slow

Im having performance issues with this query. If I remove the status column it runs very fast but adding the subquery in the column section delays way too much the query 1.02 min. How can I modify this query so it runs fast getting the desired data.
The reason I put that subquery there its because I needed the status for the latest activity, some activities have null status so I have to ignore them.
Establishments: 6.5k rows -
EstablishmentActivities: 70k rows -
Status: 2 (Active, Inactive)
SELECT DISTINCT
est.id,
est.trackingNumber,
est.NAME AS 'establishment',
actTypes.NAME AS 'activity',
(
SELECT stat3.NAME
FROM SACPAN_EstablishmentActivities eact3
INNER JOIN SACPAN_ActivityTypes at3
ON eact3.activityType_FK = at3.code
INNER JOIN SACPAN_Status stat3
ON stat3.id = at3.status_FK
WHERE eact3.establishment_FK = est.id
AND eact3.rowCreatedDT = (
SELECT MAX(est4.rowCreatedDT)
FROM SACPAN_EstablishmentActivities est4
INNER JOIN SACPAN_ActivityTypes at4
ON est4.establishment_fk = est.id
AND est4.activityType_FK = at4.code
WHERE est4.establishment_fk = est.id
AND at4.status_FK IS NOT NULL
)
AND at3.status_FK IS NOT NULL
) AS 'status',
est.authorizationNumber,
reg.NAME AS 'region',
mun.NAME AS 'municipality',
ISNULL(usr.NAME, '') + ISNULL(+ ' ' + usr.lastName, '')
AS 'created',
ISNULL(usr2.NAME, '') + ISNULL(+ ' ' + usr2.lastName, '')
AS 'updated',
est.rowCreatedDT,
est.rowUpdatedDT,
CASE WHEN est.rowUpdatedDT >= est.rowCreatedDT
THEN est.rowUpdatedDT
ELSE est.rowCreatedDT
END AS 'LatestCreatedOrModified'
FROM SACPAN_Establishments est
INNER JOIN SACPAN_EstablishmentActivities eact
ON est.id = eact.establishment_FK
INNER JOIN SACPAN_ActivityTypes actTypes
ON eact.activityType_FK = actTypes.code
INNER JOIN SACPAN_Regions reg
ON est.region_FK = reg.code --
INNER JOIN SACPAN_Municipalities mun
ON est.municipality_FK = mun.code
INNER JOIN SACPAN_ContactEstablishments ce
ON ce.establishment_FK = est.id
INNER JOIN SACPAN_Contacts con
ON ce.contact_FK = con.id
--JOIN SACPAN_Status stat ON stat.id = actTypes.status_FK
INNER JOIN SACPAN_Users usr
ON usr.id = est.rowCreatedBy_FK
LEFT JOIN SACPAN_Users usr2
ON usr2.id = est.rowUpdatedBy_FK
WHERE (con.ssn = #ssn OR #ssn = '*')
AND eact.rowCreatedDT = (
SELECT MAX(eact2.rowCreatedDT)
FROM SACPAN_EstablishmentActivities eact2
WHERE eact2.establishment_FK = est.id
)
--AND est.id = 6266
ORDER BY 'LatestCreatedOrModified' DESC
Try moving that 'activiy' query to a Left Join and see if it speeds it up.
I solved the problem by creating a temporary table and creating an index to it, this removed the need of the slow subquery in the select statement. Then I join the temp table as I do with normal tables.
Thanks to all.

Help improving SQL join

I have a stored procedure that runs to update gaming points for user balances. It's an insert with 5 subqueries. I have isolated one of the subqueries as the query that slows the entire batch down. Without it, the stored procedure will run in under 2 seconds. With it, it will take as much as 8 seconds. 8 Seconds isn't the end of the world, but for the sake of scalability, I will need to have it complete faster. Here is the isolated subquery:
(SELECT IsNull(Sum(A.TransAmount) + Sum(Case When A.BetResult = 1 Then (A.BetWinAmount + (A.TransAmount * -1)) End), 0)
FROM User_T A
LEFT OUTER JOIN User_TD B on A.TID = B.TID
LEFT OUTER JOIN Lines_BL C ON B.LID = C.LID
LEFT OUTER JOIN Lines_BM D ON C.BMID = D.BMID
LEFT OUTER JOIN Event_M E ON D.EID = E.EID
LEFT OUTER JOIN Event_KB F ON A.TransReason = F.BID
LEFT OUTER JOIN Event_M G ON F.BID = G.EID
where A.UserID = U.UserID AND (A.IsSettled = 1)
AND
(
(A.TransReason = 1 AND (datediff(dd, Convert(datetime, E.EDate, 101), Convert(datetime, #EndDate, 101)) = #DaysAgo)) OR
(A.TransReason >= 3000 AND (datediff(dd, Convert(datetime, G.EDate, 101), Convert(datetime, #EndDate, 101)) = #DaysAgo)
AND [dbo].[Event_CEAFKBID](A.TransReason) = 1) OR
(A.TransReason BETWEEN 3 and 150 AND (datediff(dd, Convert(datetime, A.TransDT, 101), Convert(datetime, #EndDate, 101)) = #DaysAgo))
)
What I have done to further isolate: When I run a Select * on just the joins (without the where clauses), the performance in very good - > 100000 rows in under a second. As I add in the where clauses, I believe the great slow down is from the 'or' clause and/or the function that needs to be evaluated.
As I understand it, a function inside the where clause evaluates each row - as opposed to somehow caching the definition of the function and evaluating that way. I do have indexes on the tables, but I am wondering if some of them are not correct.
Without you knowing the full database structure, I am sure it's very difficult to pin down where the problem is, but I would like to get pointed in a direction to begin to further isolate.
I suspect your biggest performance hits are from the correlated subquery (whatever table is behind U.UserId) and from the embedded function call dbo.Event_CEAFKBID. Much of course depends upon how big the tables are (how many rows are being read). All those datetime conversions won’t help and generate a very strong “bad design” smell, but I don’t think they’d impact performance too much.
Those left outer joins are ugly, as the optimizer has to check them all for row – so if “A” is big, all the joins on all the rows have to be performed, even if there’s no data there. If they can be replaced with inner joins, do so, but I’m guessing not because of that “table E or table G” logic. Lesses, it sure looks like what you’ve got is three separate queries moshed into one; if you broke it out into three, unioned together, it’d look something like the Frankenstein query below. I’ve no idea if this would run faster or not (heck, I can’t even debug the query and make sure the panetheses balance), but if you’ve got sparse data relative to your logic this should run pretty fast. (I took out the date conversions to make the code more legible, you’d have to plug them back in.)
SELECT isnull(sum(Total), 0) FinalTotal from (
SELECT
sum(A.TransAmount + Case When A.BetResult = 1 Then A.BetWinAmount - A.TransAmount else 0 End) Total
FROM User_T A
INNER JOIN User_TD B on A.TID = B.TID
INNER JOIN Lines_BL C ON B.LID = C.LID
INNER JOIN Lines_BM D ON C.BMID = D.BMID
INNER JOIN Event_M E ON D.EID = E.EID
where A.UserID = U.UserID
AND A.IsSettled = 1
AND A.TransReason = 1
AND (datediff(dd, E.EDate, #EndDate) = #DaysAgo))
UNION ALL SELECT
sum(A.TransAmount + Case When A.BetResult = 1 Then A.BetWinAmount - A.TransAmount else 0 End) Total
FROM User_T A
INNER JOIN Event_KB F ON A.TransReason = F.BID
INNER JOIN Event_M G ON F.BID = G.EID
where A.UserID = U.UserID
AND A.IsSettled = 1
AND A.TransReason >= 3000
AND (datediff(dd, G.EDate, #EndDate) = #DaysAgo)
AND [dbo].[Event_CEAFKBID](A.TransReason) = 1
UNION ALL SELECT
sum(A.TransAmount + Case When A.BetResult = 1 Then A.BetWinAmount - A.TransAmount else 0 End) Total
FROM User_T A
where A.UserID = U.UserID
AND A.IsSettled = 1
AND A.TransReason BETWEEN 3 and 150
AND datediff(dd, A.TransDT, #EndDate) = #DaysAgo)
) ThreeWayUnion
You can put the case in the where cause, and not directly on select first line.
why you need to put many join if in this statment you just user the tables A,E and G?
To performance better queries you can use execution plan on management Studio.
Correlated subqueries are a very poor programming technique which equates to using a cursor in the query. Make it a derived table instead.
And yes those functions are slowing you down. If you have to convert to datetime, your database structure needs to be fixed and the data stored correctly as datetime.
Do you need to do the conversions on the datetime for the DATEDIFF functions? Are you storing the dates as test, or are you reconverting to get rid of the time? If you are, then you don't need to as days different will be correct including time.
You should review whether the outer joins are necessary - they are more expensive than inner joins. You have some values that come from the dominant table, tagged A. You also have an OR condition that references E, and an OR condition that references G. I'd look to restructure the query along the lines of:
SELECT SUM(x.result)
FROM (SELECT A.TransAmount + CASE WHEN A.BetResult = 1
THEN (A.BetWinAmount + (A.TransAmount * -1))
ELSE 0 END AS result
FROM A
WHERE A.TransReason BETWEEN 3 AND 150
AND datediff(dd, Convert(datetime, A.TransDT, 101),
Convert(datetime, #EndDate, 101)) = #DaysAgo
AND A.UserID = U.UserID -- Where does alias U come from?
AND A.IsSettled = 1
UNION
SELECT A.TransAmount + CASE WHEN A.BetResult = 1
THEN (A.BetWinAmount + (A.TransAmount * -1))
ELSE 0 END AS result
FROM User_T A
JOIN User_TD B ON A.TID = B.TID
JOIN Lines_BL C ON B.LID = C.LID
JOIN Lines_BM D ON C.BMID = D.BMID
JOIN Event_M E ON D.EID = E.EID
WHERE A.TransReason = 1
AND datediff(dd, Convert(datetime, E.EDate, 101),
Convert(datetime, #EndDate, 101)) = #DaysAgo
AND A.UserID = U.UserID -- Where does alias U come from?
AND A.IsSettled = 1
UNION
SELECT A.TransAmount + CASE WHEN A.BetResult = 1
THEN (A.BetWinAmount + (A.TransAmount * -1))
ELSE 0 END S result
FROM User_T A
JOIN User_TD B ON A.TID = B.TID
JOIN Lines_BL C ON B.LID = C.LID
JOIN Lines_BM D ON C.BMID = D.BMID
JOIN Event_M E ON D.EID = E.EID
JOIN Event_KB F ON A.TransReason = F.BID
JOIN Event_M G ON F.BID = G.EID
WHERE A.TransReason >= 3000
AND datediff(dd, Convert(datetime, G.EDate, 101),
Convert(datetime, #EndDate, 101)) = #DaysAgo
AND [dbo].[Event_CEAFKBID](A.TransReason) = 1
AND A.UserID = U.UserID -- Where does alias U come from?
AND A.IsSettled = 1
) AS x
The thinking here is that the inner join queries will each be quicker than the outer join queries, and summing intermediate results is not a hardship to the DBMS (it was doing that anyway). It probably also avoids the need for IFNULL.
The alias U is, presumably, a reference to the outer query of which this is a part.