I have an sql query where I count receipts. I want to count a) all receipts, b) receipts where the related customer has registered in the same year/month, c) receipts where the related customer has visited the store at least 4 times. The query is grouped over year and month. I hope it is comprehensible.
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN
(
SELECT COUNT(DISTINCT fs_sub.Receipt)
FROM Dimension_Time AS t_sub
LEFT OUTER JOIN Fact_Sales AS fs_sub ON t_sub.ID = fs_sub.Time AND fs_sub.Store = #storeID
WHERE t_sub.Time = t.Time AND fs_sub.CustomerID = fs.CustomerID
) > 3
THEN fs.Receipt END)) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN Fact_Sales AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month
NumberOfGuests and NumberOfNewGuests works fine, but with NumberOfRegularGuests, I get an error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Is it possible to build the query another way to avoid the error?
You can put the subquery into an APPLY:
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN t2.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN Fact_Sales AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
OUTER APPLY (
SELECT COUNT(DISTINCT fs_sub.Receipt) AS countReceipts
FROM Dimension_Time AS t_sub
LEFT OUTER JOIN Fact_Sales AS fs_sub ON t_sub.ID = fs_sub.Time AND fs_sub.Store = #storeID
WHERE t_sub.Time = t.Time AND fs_sub.CustomerID = fs.CustomerID
) t2
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
But a subquery of this type is usually pretty inefficient (although this can depend on indexing as well as cardinalities ie how much of Fact_Sales is actually being used after filtering on dates). It can be replace by a windowed aggregate.
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN fs.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN (
SELECT *,
COUNT(*) OVER (PARTITION BY fs.CustomerID) AS countReceipts
FROM Fact_Sales
) AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
It's unclear why you have COUNT(DISTINCT as opposed to just COUNT, this is usually an indication of a poorly thought-out join.
If it is indeed the case that there are multiple Fact_Sales with the same Receipt then you would need to change the window aggregate, as you cannot use COUNT(DISTINCT...) OVER...
SELECT t.Year, t.Month,
COUNT(DISTINCT fs.Receipt) AS NumberOfGuests, //fs.Receipt is Receipt Number
COUNT(DISTINCT
(CASE
WHEN YEAR(c.RegistrationDate) = t.Year AND MONTH(c.RegistrationDate) = t.Month
THEN fs.Receipt END)) AS NumberOfNewGuests,
COUNT(DISTINCT
(CASE WHEN fs.countReceipts > 3 THEN fs.Receipt END)
) AS NumberOfRegularGuests
FROM Dimension_Time AS t
LEFT OUTER JOIN (
SELECT *,
MAX(rn) OVER (PARTITION BY fs.CustomerID) AS countReceipts
FROM (
SELECT *,
DENSE_RANK() OVER (PARTITION BY fs.CustomerID ORDER BY fs.Receipt) AS rn
FROM Fact_Sales
) AS fs
) AS fs ON t.ID = fs.Time AND fs.Store = #storeID
LEFT OUTER JOIN Dimension_Customer AS c ON fs.Customer = c.ID
WHERE (t.Time >= DATEFROMPARTS(2021 - 1, 5, 1)) AND (t.Time <= EOMONTH(DATEFROMPARTS(2021, 5, 1)))
GROUP BY t.Month, t.Year
ORDER BY t.Year, t.Month;
I'm working on a complicated query that I need to produce for a report. The query gives me what I need, but takes about 5 mins to run. For a report, this isn't acceptable, so I want to dump these results into a table via an overnight job and truncate the table before it runs each time. Where I'm running into trouble is how best to accomplish this, given how the query is structured, so I was hoping to get input on how I might do this. I'll break the query down as best I can into a mile-high view below:
CREATE TABLE #SALESDATA
(
...
)
INSERT INTO #SALESDATA
EXEC STAGING_DATA_PROC
WITH CTE1 AS
(
PRELIMINARY DATA 1
JOINED WITH #SALESDATA
),
CTE2 AS
(
PRELIMINARY DATA 2
JOINED WITH #SALESDATA
)
So what I first attempted to do is tried to circumvent the STAGING_DATA_PROC by just making it a query in its place, but it itself contains a few INSERTS into temp tables and doesn't seem to like the nesting of inserts in that order.
Any insight into how I might go about this?
UPDATE 1: This is the SQL that is taking about 5 mins to run. I have since replaced my SP feeding a temp table to a stand alone table that gives results instantly.
with basedata as (
select distinct a.order_num
,a.Period_Date
,a.year as std_the_year
,a.Month as std_the_month
,a.customer as std_StandardAcctNo
,b.salesperson
,isnull(ac.counter,0) [Appearance_Count]
,isnull(b.[Year],0) [The_Year]
,isnull(b.[Month],0) [The_Month]
,isnull(b.customer,0) [CustomerName]
,sum(isnull(b.Gallons,0)) [Gallon_Qty]
,sum(isnull(b.sales,0)) [Total_Sale]
,sum(isnull(b.gm,0)) [Total_Gross_Profit]
from (select distinct a.year
,a.month
,b.customer
,convert(integer,convert(varchar(4),a.Year) + right('00' + convert(varchar(2),a.month),2)) as order_num
,convert(date,convert(varchar(2),a.Month) + '/01/' + convert(varchar(4),a.Year)) as Period_Date
from IdealElephantSalesData a
join (select distinct customer from IdealElephantSalesData) b on 1 = 1
) a
join RicoCustom..Appearance_Count ac on a.customer = ac.customer_alias
left join IdealElephantSalesData b on a.customer = b.customer and a.Month = b.Month and a.Year = b.Year
group by a.order_num
,a.Period_Date
,a.year
,a.Month
,a.customer
,b.salesperson
,ac.counter
,b.[Year]
,b.[Month]
,b.customer
)
, saleslist as (
select distinct salesperson
,Appearance_Count
,Period_Date
,std_the_month
,std_the_year
,std_StandardAcctNo
,isnull(sum(Total_Gross_Profit),0) Period_GP
from basedata
group by salesperson, Appearance_Count, Period_Date, std_StandardAcctNo,std_the_month,std_the_year
), core_GP as (
select distinct a.customer
,convert(date,convert(varchar(2),a.month) + '/01/' + convert(varchar(4),a.year)) as Period_Date
,sum(a.gm) as Period_GP
from IdealElephantSalesData a
join RicoCustom..Appearance_Count ac on ac.customer_alias = a.customer
group by counter, convert(date,convert(varchar(2),a.month) + '/01/' + convert(varchar(4),a.year)), a.customer
), GroupedData AS (
SELECT distinct cgp.std_StandardAcctNo, cgp.Period_Date, sum(cgp.[Total_Gross_Profit]) as Period_GP, Appearance_Count
FROM basedata cgp
group by cgp.std_StandardAcctNo, cgp.Period_Date, Appearance_Count
), GP_Grouping as (
select std_StandardAcctNo
,min(Period_Date) as range_start
,max(Period_Date) as range_end
,count(*) as range_count
,GP_group
from (
select std_StandardAcctNo, Period_Date, case when Period_GP = 0 then 0 else 1 end as GP_Group
,row_number() over (PARTITION BY std_StandardAcctNo, case when Period_GP = 0 then 0 else 1 end order by Period_Date) as rn
,row_number() over (PARTITION BY std_StandardAcctNo, case when Period_GP = 0 then 0 else 1 end order by Period_Date) - row_number() over (PARTITION BY std_StandardAcctNo order by Period_Date) as grp
,row_number() over (PARTITION BY std_StandardAcctNo order by Period_Date) as grp2
from GroupedData
) a
group by std_StandardAcctNo, grp, GP_Group
),GP_Group2 as (
select gd.*, max(gpg_prev.range_end) as last_zero_group
FROM GroupedData gd
left join GP_Grouping gpg on gd.std_StandardAcctNo = gpg.std_StandardAcctNo and gd.Period_Date between gpg.range_start and gpg.range_end
left join (select * from GP_Grouping where GP_Group = 0 and range_count >= 12) gpg_prev on gpg_prev.std_StandardAcctNo = gd.std_StandardAcctNo and gpg.range_start > gpg_prev.range_end
group by gd.std_StandardAcctNo, Period_Date, Period_GP, Appearance_Count, gpg.range_count
), GP_Group3 as (
SELECT gd.*
,Appearance_Cnt_Rel = case when gd.last_zero_group is null then Appearance_Count else ROW_NUMBER() OVER(PARTITION BY gd.std_StandardAcctNo, gd.last_zero_group ORDER BY gd.Period_Date) end
FROM GP_Group2 gd
), almost_done as (
select distinct bd.order_num
,bd.Period_Date
,bd.std_the_year
,bd.std_the_month
,bd.std_StandardAcctNo
,case when bd.[Appearance_Count] > 0 then bd.[Appearance_Count]
when isnull(c.Appearance_Count,0) > 0 then c.Appearance_Count + 1
when isnull(d.Appearance_Count,0) > 0 then d.Appearance_Count + 2
when isnull(e.Appearance_Count,0) > 0 then e.Appearance_Count + 3
else 0
end as Appearance_Count
,bd.[The_Year]
,bd.[The_Month]
,bd.[CustomerName]
,bd.[Gallon_Qty]
,bd.[Total_Sale]
,isnull(c.Appearance_Count,0) as Prev_Count
,isnull(d.Appearance_Count,0) as month2_Count
,isnull(e.Appearance_Count,0) as month3_Count
,case when bd.salesperson is not null then bd.salesperson
when c.salesperson is not null then c.salesperson
when d.salesperson is not null then d.salesperson
when e.salesperson is not null then e.salesperson
else 'NA' end [SalesPerson]
,case when bd.[Appearance_Count] is null and c.[Appearance_Count] is null and d.[Appearance_Count] is null then e.Period_GP else 0 end [Lost_Gross_Profit]
,case when bd.Appearance_Count = 1 then bd.Total_Gross_Profit else 0 end as 'New_Cust_GP'
,case when bd.Appearance_Count <= 12 then bd.Total_Gross_Profit else 0 end as 'Young_Cust_GP'
,case when bd.Appearance_Count > 12 then bd.Total_Gross_Profit else 0 end as 'Old_Cust_GP'
,ROW_NUMBER() OVER (PARTITION BY bd.std_StandardAcctNo, bd.std_The_Year, bd.std_The_Month ORDER BY (bd.std_StandardAcctNo) DESC) as UNI_Period
,bd.Total_Gross_Profit as SalesP_GP
,isnull(cg.Period_gp,0) as Period_gp
,case when isnull(b_prev.Period_gp,0) > 0 then isnull(b_prev.Period_gp,0)
when isnull(d.Period_gp,0) > 0 then isnull(d.Period_gp,0)
when isnull(e.Period_gp,0) > 0 then isnull(e.Period_gp,0)
else 0 end as Prev_Period_GP
,h.Mat_MoM_Shift
,case when isnull(b_prev.Period_gp,0) > 0 then isnull(b_prev.Period_gp,0)
when isnull(d.Period_gp,0) > 0 then isnull(d.Period_gp,0)
when isnull(e.Period_gp,0) > 0 then isnull(e.Period_gp,0)
else 0 end * h.Mat_MoM_Shift as Expected_GP
,isnull(c.Period_gp,0) as True_Prev_GP
,isnull(d.Period_gp,0) as True_2month_GP
,isnull(e.Period_gp,0) as True_3month_GP
,ideal_candidate = case when ((isnull(c.Period_gp,0) + isnull(d.Period_gp,0) + isnull(bd.Total_Gross_Profit,0)) / 3 >= 800) and isnull(c.Period_gp,0) >= 150 and isnull(d.Period_gp,0) >= 150 and isnull(bd.Total_Gross_Profit,0) >= 150 then 'Y' else 'N' end
,eleph_candidate = case when ((isnull(c.Period_gp,0) + isnull(d.Period_gp,0) + isnull(bd.Total_Gross_Profit,0)) / 3 >= 5000) and isnull(c.Period_gp,0) >= 1000 and isnull(d.Period_gp,0) >= 1000 and isnull(bd.Total_Gross_Profit,0) >= 1000 then 'Y' else 'N' end
from basedata bd
left join core_GP b_prev on bd.std_StandardAcctNo = b_prev.customer and b_prev.Period_Date = dateadd(month,-1,bd.Period_Date)
left join saleslist c on c.std_StandardAcctNo = bd.std_StandardAcctNo and c.Period_Date = dateadd(month,-1,bd.Period_Date) and case when bd.salesperson is not null then bd.salesperson else c.salesperson end = c.salesperson
left join saleslist d on d.std_StandardAcctNo = bd.std_StandardAcctNo and d.Period_Date = dateadd(month,-2,bd.Period_Date) and case when bd.salesperson is not null then bd.salesperson when c.salesperson is not null then c.salesperson else d.salesperson end = d.salesperson
left join saleslist e on e.std_StandardAcctNo = bd.std_StandardAcctNo and e.Period_Date = dateadd(month,-3,bd.Period_Date) and case when bd.salesperson is not null then bd.salesperson when c.salesperson is not null then c.salesperson when d.salesperson is not null then d.salesperson else e.salesperson end = e.salesperson
left join RicoCustom.dbo.[Rico_Global_Monthly] h on h.month = bd.std_the_month
left join core_GP cg on bd.std_StandardAcctNo = cg.customer and cg.Period_Date = bd.Period_Date
),get_ideal as (
select distinct min(ad.Period_Date) as ideal_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
from almost_done ad
left join GP_Group3 rc on rc.Period_Date = ad.Period_Date and rc.std_StandardAcctNo = ad.std_StandardAcctNo and rc.Period_GP = ad.Period_gp
where ideal_candidate = 'Y' and (rc.Appearance_Cnt_Rel between 3 and 6)
group by ad.std_StandardAcctNo,rc.last_zero_group
), get_elephant as (
select distinct min(ad.Period_Date) as eleph_Period_Date
,ad.std_StandardAcctNo
,rc.last_zero_group
from almost_done ad
left join GP_Group3 rc on rc.Period_Date = ad.Period_Date and rc.std_StandardAcctNo = ad.std_StandardAcctNo and rc.Period_GP = ad.Period_gp
where eleph_candidate = 'Y' and (rc.Appearance_Cnt_Rel between 3 and 36)
group by ad.std_StandardAcctNo,rc.last_zero_group
)
select rc.Appearance_Cnt_Rel
,gi.ideal_Period_Date
,ge.eleph_Period_Date
,ad.*
from almost_done ad
left join GP_Group3 rc on rc.Period_Date = ad.Period_Date and rc.std_StandardAcctNo = ad.std_StandardAcctNo and rc.Period_GP = ad.Period_gp
left join get_ideal gi on ad.std_StandardAcctNo = gi.std_StandardAcctNo and ad.Period_Date = gi.ideal_Period_Date
left join get_elephant ge on ad.std_StandardAcctNo = ge.std_StandardAcctNo and ad.Period_Date = ge.eleph_Period_Date
where order_num > 201001
GO
Have you tried breaking your complicated query into smaller queries that load the data into temporary tables. You can use the temporary tables to build your final result. With the temporary tables, you can build the necessary indexes against them to ensure better performance. Additionally, you will be working with smaller subsets of the data which should result in better performance.
I'm trying to do a SUM against all items which match a certain condition, like so:
SELECT l.Building_Name,
SUM(CASE WHEN s.Date >= '20180930' THEN 1 ELSE 0 END) Validated,
COUNT(DISTINCT s.id) Total
FROM Lab_Space s
JOIN Locations l ON s.Building_Code = l.Building_Code
GROUP BY l.Building_Name
The COUNT there is correct, and will say something like 20 because I can put the DISTINCT s.id in there. However, my SUM ends up with something like 1500. This is because when I do the JOIN rows are duplicated multiple times, and thus the SUM is counting against each one.
How can I do a SUM/CASE like this but make sure it only applies to distinct rows?
s.id l.building_name s.date
1 JF 2018-11-10
1 JF 2018-11-10
2 JF 2018-12-12
So if I have data like that, I'm going to get my count properly of 2, but validate will say 3 because the id of 1 appears twice due to doing a JOIN
You can edit this code of temp table if you deem fit.
create table #temp_Lab_Space
([Date] date null
,Building_Code int null
)
create table #temp_Locations
( Building_Code int null
,Building_Name varchar(10) null
)
insert into #temp_Lab_Space values
('2018-11-10',1)
,('2018-11-10', 1)
,('2018-12-12' , 1)
insert into #temp_Locations values
(1, 'JF')
select Building_Name,
SUM(CASE WHEN Date >= '20180930' THEN 1 ELSE 0 END) Validated,
COUNT(DISTINCT Building_Code) Total
from (
select distinct l.Building_Name, s.Building_Code, s.Date
,Rank_1 = rank() over(partition by l.Building_Name order by s.Date asc)
FROM #temp_Lab_Space s
JOIN #temp_Locations l ON s.Building_Code = l.Building_Code
) a
group by Building_Name
wild guess
select l.Building_Name
, count(s.Id)
, sum(s.Validated)
from Locations l
cross apply ( select s.Id
, max(case
when s.Date >= '20180930' then 1
else 0
end) as Validated
from Lab_Space s
where s.Building_Code = l.Building_Code
group by s.Id) s
group by l.Building_Name
should give you the distinct space.id and a flag whether it is validated.
I want to pass a ShowRoomId value to the query below. The Employees table has a ShowRoomId column.
How can I do it?
My SQL query is as following:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
Simply use a WHERE clause at the end as following:
... YOUR SELECT ...
WHERE Col = ...YourCondition...
OR
Use WITH keyword to keep your current SELECT-statement in a cte. Then do your query on it.
WITH cte AS
(
... YOUR SELECT ...
)
SELECT *
FROM cte
WHERE Col = ...YourCondition...
OR
You can add your SELECT-statement in to parentheses and name it with an allias name. So you can do query on it too.
SELECT *
FROM
(
... YOUR SELECT ...
) t
WHERE t.Col = ...YourCondition...
As per Giorgi Nakeuri's advice, I added the WHERE clause at the end of the statement.
And it works for me. Revised code is here:
SELECT *
FROM Employees A
OUTER APPLY (SELECT TOP 1 *
FROM EmployeeBasics B
WHERE (A.EmployeeID = B.EmployeeID)
ORDER BY B.BasicUpdateDate DESC) AS B
OUTER APPLY (
SELECT C.EmployeeId , count(*) AS TotalAbsent
FROM EmployeeAbsents C
WHERE C.AbsentDate BETWEEN '2016-05-01' AND '2016-05-30' AND A.EmployeeID = C.EmployeeID
GROUP BY C.EmployeeId
) AS C
OUTER APPLY (
SELECT EmployeeId,
SUM(CASE WHEN TransctionTypeId = 1 THEN Amount ELSE 0 END) AS Payment,
SUM(CASE WHEN TransctionTypeId = 2 THEN Amount ELSE 0 END) AS RecoverSalary,
SUM(CASE WHEN TransctionTypeId = 3 THEN Amount ELSE 0 END) AS RecoverCash
FROM dbo.EmployeeAdvances D
WHERE A.EmployeeID = D.EmployeeID
GROUP BY EmployeeId
) AS D
WHERE A.ShowRoomId = 2
I have this query:
SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN ISNUMERIC(dtLu.sLu) = 1 THEN CONVERT(INT, dtLu.sLu) ELSE 9999999 END asc, dtLu.sLu) as row,
dtLu.*, dtLuDerived.cCll, dtMtrDerived.cMtrCll, dtMtrDerived.cMtrCllIn, dtMtrDerived.cMtrCllOut FROM dtLu
LEFT OUTER JOIN (
SELECT pLu, COUNT(pLu) AS cCll
FROM dtCll
GROUP BY pLu)
AS dtLuDerived ON dtLu.pLu = dtLuDerived.pLu
LEFT OUTER JOIN (
SELECT dtCll.pLu, SUM(cMtrCll) AS cMtrCll, SUM(cMtrCllIn) AS cMtrCllIn, SUM(cMtrCllOut) AS cMtrCllOut
FROM dtMtrCll
INNER JOIN dtCll on dtCll.pCll = dtMtrCll.pCll
WHERE dtCll.pWhr IN (SELECT DISTINCT pWhr FROM dtUserWhr WHERE pUser = 5)
GROUP BY dtCll.pLu)
AS dtMtrDerived ON dtLu.pLu = dtMtrDerived.pLu
INNER JOIN dtLct on dtLct.pLct = dtLu.pLct
WHERE dtLu.pLu > 0 AND dtLct.pLctAsl IN (select pAsl from dtAsl where pAslUnt = 1)
-- this is the ORDER I need
ORDER BY dtLu.pLct DESC
) a
WHERE a.row > 0 and a.row <= 17
but if I use the order ORDER BY dtLu.pLct DESC it gives me error...
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP, OFFSET
or FOR XML is also specified.
I searched, found various samples, but my subquery is different, 'cause is needed to retrieve only 17 rows per page (next page will have the last line like this: WHERE a.row > 17 and a.row <=35)
how can I select the top 17 rows but with an order inside?
thanks
You are trying to put the order in your inner query which doesn't work. Move the order by to the main query. Also, you should list your columns instead of using *. You could probably improved this query a bit with fewer subselects but that is outside the scope of your question.
SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN ISNUMERIC(dtLu.sLu) = 1 THEN CONVERT(INT, dtLu.sLu) ELSE 9999999 END asc, dtLu.sLu) as row,
dtLu.* --you should list the columns out here
, dtLuDerived.cCll, dtMtrDerived.cMtrCll, dtMtrDerived.cMtrCllIn, dtMtrDerived.cMtrCllOut FROM dtLu
LEFT OUTER JOIN (
SELECT pLu, COUNT(pLu) AS cCll
FROM dtCll
GROUP BY pLu)
AS dtLuDerived ON dtLu.pLu = dtLuDerived.pLu
LEFT OUTER JOIN (
SELECT dtCll.pLu, SUM(cMtrCll) AS cMtrCll, SUM(cMtrCllIn) AS cMtrCllIn, SUM(cMtrCllOut) AS cMtrCllOut
FROM dtMtrCll
INNER JOIN dtCll on dtCll.pCll = dtMtrCll.pCll
WHERE dtCll.pWhr IN (SELECT DISTINCT pWhr FROM dtUserWhr WHERE pUser = 5)
GROUP BY dtCll.pLu)
AS dtMtrDerived ON dtLu.pLu = dtMtrDerived.pLu
INNER JOIN dtLct on dtLct.pLct = dtLu.pLct
WHERE dtLu.pLu > 0 AND dtLct.pLctAsl IN (select pAsl from dtAsl where pAslUnt = 1)
-- this is the ORDER I need
--ORDER BY dtLu.pLct DESC
) a
WHERE a.row > 0 and a.row <= 17
order by a.pLct
Use TOP 100 Percent in Subquery
SELECT *
FROM (SELECT top 100 percent Row_number()
OVER (
ORDER BY CASE WHEN Isnumeric(dtLu.sLu) = 1 THEN CONVERT(INT, dtLu.sLu) ELSE 9999999 END ASC, dtLu.sLu) AS row,
dtLu.*,
dtLuDerived.cCll,
dtMtrDerived.cMtrCll,
dtMtrDerived.cMtrCllIn,
dtMtrDerived.cMtrCllOut
FROM dtLu
LEFT OUTER JOIN (SELECT pLu,
Count(pLu) AS cCll
FROM dtCll
GROUP BY pLu) AS dtLuDerived
ON dtLu.pLu = dtLuDerived.pLu
LEFT OUTER JOIN (SELECT dtCll.pLu,
Sum(cMtrCll) AS cMtrCll,
Sum(cMtrCllIn) AS cMtrCllIn,
Sum(cMtrCllOut) AS cMtrCllOut
FROM dtMtrCll
INNER JOIN dtCll
ON dtCll.pCll = dtMtrCll.pCll
WHERE dtCll.pWhr IN (SELECT DISTINCT pWhr
FROM dtUserWhr
WHERE pUser = 5)
GROUP BY dtCll.pLu) AS dtMtrDerived
ON dtLu.pLu = dtMtrDerived.pLu
INNER JOIN dtLct
ON dtLct.pLct = dtLu.pLct
WHERE dtLu.pLu > 0
AND dtLct.pLctAsl IN (SELECT pAsl
FROM dtAsl
WHERE pAslUnt = 1)
-- this is the ORDER I need
ORDER BY dtLu.pLct DESC) a
WHERE a.row > 0
AND a.row <= 17