How to place subquery in SQL Server 2008 - sql-server

I have a main SQL query which returns stock quantity in dates between and I also need to return the stock as on date along with between dates result.
Main query:
SELECT
TT.TranRId, MAX(TT.TInQty) AS InQty, MAX(TT.TOutQty) AS OutQty
FROM
TReg TR, TTrans TT
WHERE
TR.TRegId = TT.TrRegId
AND TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY
TT.TranRId
ORDER BY
TT.TranRId
Sub query:
(SELECT TT.TransRId, (SUM(TT.TInQty) - SUM(TT.TOutQty))
FROM TTrans TT, TReg TR
WHERE TR.TransDate <= '2018-08-24'
AND TR.TRegId = TT.TrRegId
AND TT.Stid = 2 GROUP BY TT.TranRId) --AS Stock
Please help where I should include my sub query in my main query
To get output as follows:
TransRId Stock InQty OutQty
----------------------------------
41 700 1 1000
42 800 5 500

I am not sure I am following your question 100%, if you are just looking to join it as a sub query the below logic should work.
SELECT TT.TranRId
,MAX(TT.TInQty) AS InQty
,MAX(TT.TOutQty) AS OutQty
,Stock.[Sum]
FROM TReg TR
LEFT JOIN TTrans TT
ON TR.TRegId = TT.TrRegId
LEFT JOIN (
SELECT TT.TransRId
,(SUM(TT.TInQty) - SUM(TT.TOutQty)) as Sum
FROM TTrans TT
LEFT JOIN TReg TR
ON TR.TRegId = TT.TrRegId
WHERE TR.TransDate <= '2018-08-24'
AND TT.Stid = 2
GROUP BY TT.TranRId
) AS Stock
ON Stock.TranRId = TT.TranRId
WHERE TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY TT.TranRId
ORDER BY TT.TranRId
edit:
I noticed tt.TranRId and tt.Tran***s***RId if this is not a typo it would need to be corrected, if not my answer will not work for you.
If you need specific dates, including the date in the join logic along with the ID would give you the appropriate result...without knowing your data set I am not sure if the TranRId is unique...sorry about that!

Related

Pivot Values as Column Headers

I have some questions in a table named GeneralReviews_Questions q that I want to use as column headers rather than values. I'm accomplishing this now by sticking the question responses into a #temp table and then joining a second query to get the responses and hard-coding the questions as column names. It works but it's a maintenance nightmare. How do I accomplish this without hard-coding the questions as column names?
SELECT
r.ReviewID,
max(case when q.Sequence = 1 AND q.Category = 'General' AND q.Active = 1 then Response end)
AS [Q1],
max(case when q.Sequence = 2 AND q.Category = 'General' AND q.Active = 1 then Response end)
AS [Q2]
INTO #temp
FROM
GeneralReviews gr INNER JOIN GeneralReviews_Questions_Responses r
ON gr.ReviewID = r.ReviewID INNER JOIN
GeneralReviews_Questions q ON r.QuestionID = q.QuestionID
GROUP BY
r.ReviewID;
SELECT
#temp.ReviewID AS ReviewID
,#temp.[Q1] AS [Q1 For the past four quarters, were the Quarterly Interest Statements sent
if the account and loan type/status required it?]
,#temp.[Q2] AS [Q2 We will focus on 1-2 events (repay plan change, new disbursement, end of
a defer/forb, acct adjustment etc) per qtr?]
FROM
GeneralReviews gr INNER JOIN
#temp ON gr.ReviewID = #temp.ReviewID
Desired Results: https://i.stack.imgur.com/HPnS3.jpg

Optimise query with count and order by function

I have a problem with the optimization of this query, I have 3 tables (Products = Catalogo.GTIN, Sales Header = TEDEF.Factura and Sales Detail = TEDEF.Farmacia).
The query tries to find the Mode of the column VPRODEXENIGV_FAR. This query without the ORDER BY executes in less than 3 seconds (the table of details has about 30 million rows).
But when I add the ORDER BY clause, the query now takes more than 30 minutes to run.
I want to know how can I optimize this query or the indexes that I need to optimize this.
SELECT *
FROM Catalogo.GTIN G
CROSS APPLY
(SELECT TOP 1
COUNT(FAR.VPRODEXENIGV_FAR) [ROW],
YEAR(FAC2.VFECEMI_FAC) [AÑO],
MONTH(FAC2.VFECEMI_FAC) [MES],
FAR.VCODPROD_FAR_003,
CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM
TEDEF.Factura FAC2
INNER JOIN
TEDEF.Farmacia FAR ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
WHERE
G.CODIGO = FAR.VCODPROD_FAR_003
GROUP BY
YEAR(FAC2.VFECEMI_FAC),
MONTH(FAC2.VFECEMI_FAC),
FAR.VCODPROD_FAR_003,
FAR.VPRODEXENIGV_FAR
ORDER BY
1 DESC --- <----- THE PROBLEM IS HERE
) GG
Ouch! You have a hugely expensive dependent subquery. It's expensive because SELECT TOP(n) ... ORDER BY col DESC does a whole lot of work to create a result set only to discard all but one row. And, it's a dependent subquery so it's run for every row of Catalogo.GTIN .
It looks like you want to count the resultset rows in the most recent month and year for each Catalogo.GTIN row. So, let's try to refactor your query to do that.
We'll start with a subquery to grab the month-start date of the latest Factura row for each catalog entry.
SELECT CODIGO,
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes
FROM (
SELECT MAX(FAC2.VFECEMI_FAC) maxd,
G.CODIGO
FROM Catalogo.GTIN G
JOIN TDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
GROUP BY G.CODIGO
) maxd
It's wise to test this and make sure it works correctly and performs tolerably well. If you test it in SSMS, you can use "Show Actual Execution Plan" and see if it recommends an extra index. This subquery need only be run once, rather than once per G.CODIGO row.
Then we'll use it in your larger query.
SELECT G.*,
COUNT(FAR.VPRODEXENIGV_FAR) [ROW],
YEAR(FAC2.VFECEMI_FAC) [AÑO],
MONTH(FAC2.VFECEMI_FAC) [MES],
FAR.VCODPROD_FAR_003,
CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM Catalogo.GTIN G
JOIN (
SELECT CODIGO,
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes
FROM (
SELECT MAX(FAC2.VFECEMI_FAC) maxd,
G.CODIGO
FROM Catalogo.GTIN G
JOIN TDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
GROUP BY G.CODIGO
) maxd
) maxmes ON G.CODIGO = maxmes.CODIGO
JOIN TEDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
AND FAC2.VFECEMI_FAC >= maxmes.maxmes
GROUP BY maxmes.maxmes,
G.CODIGO,
FAR.VCODPROD_FAR_003,
FAR.VPRODEXENIGV_FAR
Here is the tricky bit:
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes turns any date maxd into the first day of that month.
And, FAC2.VFECEMI_FAC >= maxmes.maxmes filters out rows before the first day of that month (for that CODIGO). It does so in a sargable way: a way that can exploit an index on FAC2.VFECEMI_FAC.
That is an alternative way to do TOP(1) ORDER BY d DESC. And faster.
It's all about sets of rows. Especially when using GROUP BY, it's performance-helpful to limit the number of rows in each set.
Obviously I cannot debug this.
Is me again, Finally i resolve the problem of the optimization, now the query delay is about 20 sec (with the sort instruction and with the count in a table over 30 million rows) i hope this way can help others or could be optimice more by the community.
I resolve the problem applying the sort but with the Row_Number instruction, in that way the server take my index for the sort instruction and make the magic:
WITH x
AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY GG.COD, GG.[AÑO], GG.[MES] ORDER BY GG.[ROW] DESC) [ID]
FROM Catalogo.GTIN G
CROSS APPLY
(
SELECT COUNT(FAR.VPRODEXENIGV_FAR) [ROW]
, YEAR(FAC2.VFECEMI_FAC) [AÑO]
, MONTH(FAC2.VFECEMI_FAC) [MES]
, FAR.VCODPROD_FAR_003 [COD]
, CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM TEDEF.Factura FAC2
INNER JOIN TEDEF.Farmacia FAR
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
WHERE G.CODIGO = FAR.VCODPROD_FAR_003
GROUP BY YEAR(FAC2.VFECEMI_FAC)
, MONTH(FAC2.VFECEMI_FAC)
, FAR.VCODPROD_FAR_003
, FAR.VPRODEXENIGV_FAR
-- ORDER BY 1 DESC --- <---- this is the bad guy, please, don't do that xD
) GG
) SELECT *
FROM x WHERE ID = 1
In that way i can sort the Count instruction and calculate the Mode for the Column FAR.VPRODEXENIGV_FAR

Oracle get only last 1 row data on multiple tables query

I have an Oracle query to get only last 1 row data.
SELECT
R.FORM_NO,
R.PART_NO,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO,
S.PART_NO,
S.CP_ID
FROM
WA_T_QC_REVISION R,
WA_T_QC_REVISION_LIST L,
WA_T_QC_CP_SELECTED S
WHERE
R.FORM_NO = L.HDR_ID AND
S.FORM_NO = L.CP_ID_SLC_FORM_NO AND
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC
When I try to adding the query to be like this:
SELECT * FROM(
SELECT
R.FORM_NO,
R.PART_NO,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO,
S.PART_NO,
S.CP_ID
FROM
WA_T_QC_REVISION R,
WA_T_QC_REVISION_LIST L,
WA_T_QC_CP_SELECTED S
WHERE
R.FORM_NO = L.HDR_ID AND
S.FORM_NO = L.CP_ID_SLC_FORM_NO AND
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC)
WHERE ROWNUM <= 1
I got an error
ORA-00918: column ambiguously defined
What I want is to get only last 1 row data from tables.
The immediate fix here is to just alias the columns having the same name such that they no longer have the same name, e.g.
SELECT * FROM (
SELECT
R.FORM_NO AS FORM_NO_R,
R.PART_NO AS PART_NO_R,
L.L_FORM_NO,
L.HDR_ID,
L.CP_ID_SLC_FORM_NO,
S.FORM_NO AS FORM_NO_S,
S.PART_NO AS PART_ON_S,
S.CP_ID
FROM WA_T_QC_REVISION R
INNER JOIN WA_T_QC_REVISION_LIST L
ON R.FORM_NO = L.HDR_ID
INNER JOIN WA_T_QC_CP_SELECTED S
ON S.FORM_NO = L.CP_ID_SLC_FORM_NO
WHERE
R.PART_NO = 'PA03670-B501'
ORDER BY R.FORM_NO DESC
)
WHERE ROWNUM <= 1
Note also that I replaced your implicit joins with explicit inner joins. Using formal join syntax is the preferred way of writing queries (and has been for more than 25 years).

How to display only the MAX results from a query

I am new to writing MS SQL queries and I am trying to display only the record with the highest field named RecordVersion.
Below is the query that works but displays all records:
SELECT
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
Here are the query results:
PriceProgramID EffectiveDateTime Price PLU Descr LastUpdate LastUpdatedBy RecordVersion PriceScheduleUniqueID
1 2016-03-22 00:00:00.000 35.00 SLS10100103 Architecture Adult from NP POS 2015-01-22 07:53:15.000 GX70,83 9 569
1 2016-03-22 00:00:00.000 32.00 SLS10100103 Architecture Adult from NP POS 2014-02-25 16:22:46.000 GX70,83 5 86180
The first line of the results has RecordVersion being 9 and the second line results is 5, I only want the higher record displaying, the one that returned RecordVersion = 9.
Every time I try to use the MAX command I get errors or the group by and I have tried every example I could find on the web but nothing seems to work.
Using MS SQL 2012.
Thanks,
Ken
Try the following query which attempts to solve your problem by ordering the returned rows by RecordVersion DESC and then SELECTs just the first row.
SELECT TOP 1
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
ORDER BY
RecordVersion DESC
All group by columns should be in select ,that's the rule of group by.How group by works is for every distinct combination of group by columns,arrange remaining columns into groups,so that any aggregation can be applied,in your case I am not sure what group by columns are unique with out test date.here is one version which use row number which gives you the output desired
Remember ,order by last updated date is the one which decides rows order and assign numbers
WITH CTE
AS
(
SELECT PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID,
ROW_NUMBER() OVER (PARTITION BY PriceSchedules.RecordVersion ORDER BY PriceSchedules.LastUpdatedBy) AS RN
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
)
SELECT * FROM CTE WHERE RN=1

Find Previous record by date stored in another Table

So i have 2 tables, one keeps the record of the cash on tjhe cash register at the end of the day and how much money is left for the next day, the other keeps a record of basicly the date of the record (tables cannot be joined) All that looks like this:
RegistersTable
------------------
Register_ID| DATE
5 | 02/02/2012
8 | 04/02/2012
1 | 10/02/2012
CashTable
----------------
Register_ID|CashEOD|CashFND
8 |3235 |325
5 |6843 |435
1 |1236 |1953
So what im trying to get is a select statement that should return this
RegisterID| DATE|CashEOD|PrevCashFND
1 |10/02/2012|1236 |325
8 |04/02/2012|3235 |435
5 |02/02/2012|6843 |0/Null
Start with a RegisterID on the CashTable, find the previous RegisterID by the DATE in RegistersTable, get the previous CashFND so the final goal is to know how much was selled on that day.
Cash End of Day minus the Cash left on the register from the previous day should tell me that. Thanks in advance.
Please try the following - I hope it helps:
SELECT
D.RegisterID,
D.[DATE],
CashTable.CashEOD,
CashTable_Prev.CashFND AS PrevCashFND
FROM
(
SELECT
A.RegisterID,
A.[DATE],
B.RegisterID AS PrevID
FROM
RegistersTable A
INNER JOIN RegistersTable B ON A.RegisterID <> B.RegisterID AND A.[DATE] > B.[DATE]
INNER JOIN
(
SELECT
_innA.RegisterID,
_innB.RegisterID As PrevID,
MIN(_innA.[DATE] - _innB.[DATE]) AS MinDateDiff
FROM
RegistersTable _innA
INNER JOIN RegistersTable _innB ON _innA.RegisterID <> _innB.RegisterID AND _innA.[DATE] > _innB.[DATE]
GROUP BY
_innA.RegisterID,
_innB.RegisterID
) C
ON A.RegisterID = C.RegisterID AND B.RegisterID = C.PrevID AND (A.[DATE] - B.[DATE]) = C.MinDateDiff
) AS D
INNER JOIN CashTable
ON CashTable.Register_ID = D.RegisterID
INNER JOIN CashTable AS CashTable_Prev
ON CashTable_Prev.Register_ID = D.PrevID

Resources