I am using the SUM Over the first time and have the following query noe:
SELECT Id, Amount, Date, TotalAmount = SUM(Amount) OVER (order by Amount)
FROM Account
WHERE Date >= '2016-03-01' AND Date <= '2016-03-10' AND UserId = 'xyz'
ORDER BY ValutaDate
The TotalAmount should be a running total over the whole table for a specific user (so the Sum Over clause should respect the where clause for the user). On the other hand I just need a few records and not the whole table, thats why I added the where clause specifying the date range. But now, of course, my sum gets calculated just for the range I specified.
What should I do, to get just a few records specified by date range but get the sum calculated over the whole table though. Is there an performant way to accomplish this?
Thanks in advance for helping me out.
Break the running total into its own query
; WITH all_rows_one_user as (SELECT *
, TotalAmount = SUM(Amount) OVER (order by ValutaDate)
FROM Account
WHERE UserId = 'xyz')
SELECT Id, Amount, Date, TotalAmount
FROM all_rows_one_user
WHERE Date >= '2016-03-01' AND Date <= '2016-03-10'
ORDER BY ValutaDate
Same query, different syntax:
SELECT Id, Amount, Date, TotalAmount
FROM (SELECT *
, TotalAmount = SUM(Amount) OVER (order by ValutaDate)
FROM Account
WHERE UserId = 'xyz') AS all_rows_one_user
WHERE Date >= '2016-03-01' AND Date <= '2016-03-10'
ORDER BY ValutaDate
The WHERE clause is applied first so the SUM can't access rows that don't match that.
You can use apply though. Note it will be reading the entire table for that user so might not perform too well without a decent index.
SELECT a.Id, a.Amount, a.Date, ta.TotalAmount
FROM Account a
OUTER APPLY (SELECT SUM(CASE WHEN a2.Date <= Account.Date THEN a2.TotalAmount ELSE 0 END) AS TotalAmount FROM Account a2 WHERE a2.UserId = Account.UserId) ta
WHERE a.Date >= '2016-03-01' AND a.Date <= '2016-03-10' AND a.UserId = 'xyz'
Related
I'm trying to get a count of unique items in a column given an ID number and where the date is within the last 12 months. I need to iterate this over each row in my table.
I am using a combination of dense_rank() and (Over partition by to calculate the count of unique items, but I haven't been able to add in the date filter successfully. The results I see so far are showing count of distinct Unique_Code for each row with the same ID regardless of the date.
select ID,
Unique_Code,
Transaction_Date,
DATEADD(Month, -12, Transaction_Date) as L12M,
dense_rank() over (partition by ID order by Transaction_Date, Unique_Code) as [Unique_Count]
from (select *, (case when datediff(day, lag(Transaction_Date,1,Transaction_Date) over (partition by Unique_Code order by ID), Transaction_Date)
<= 1
then 1 else 2
end) as grp
from datatable1)
I expect the results to show a count of unique items from the unique_code column for the id in the row and where previous entries within the same ID are with the transaction date and the transaction date - 12 months. Right now I am seeing a count of unique items from the unique_code column from each entry with the same ID regardless of the date range.
Unfortunately I do not have your source data to test, however, I've added an extra column to yours below:
select
ID
, Unique_Code
, Transaction_Date
, DATEADD(Month, -12, Transaction_Date) as L12M
, dense_rank() over (partition by ID order by Transaction_Date, Unique_Code) as [Unique_Count]
, rank() over (partition by Transaction_Date order by ID) NewUniqueCount
from (select *, (case when datediff(day, lag(Transaction_Date,1,Transaction_Date) over (partition by Unique_Code order by ID), Transaction_Date) <= 1
then 1 else 2 end) as grp from datatable1)
Let me know if it works? - It should work.
this is driving me crazy! does anyone know how to write some SQL that will return the MIN and MAX dates from groups of sequential numbers? please see screen shots below.
This is the SQL I used:
SELECT
num
, empid
, orderdate
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY orderdate) AS Num
, empid
, orderdate
FROM TSQL.Sales.Orders)T1
WHERE empid = 4
This is what it returns:
What I would like to do is get the Min and Max dates for each set of sequential numbers based on the num column. For example: the first set would be num 3, 4, 5 & 6. so the Min date is 2006-07-08 and the Max date is 2006-07-10
See example of results needed below
Any help with this would be much appreciated, thank you in advance
Update
I have now changed the SQL to do what I needed: example as follows:
Select
empid
, Island
, MIN(orderdate) as 'From'
, Max(orderdate) as 'To'
From
(select
empid
, num
, num - ROW_NUMBER() OVER (ORDER BY num, orderdate) as Island
, orderdate
from
(Select
ROW_NUMBER() OVER (ORDER BY orderdate) as Num
, empid
, orderdate
from TSQL.Sales.Orders)T1
where empid = 4
)T2
group By
empid
, Island
Result
Thank you so much for your help on this, I have been trying this for ages
Regards
Jason
This should do it:
;with dateSequences(num, empId, orderDate) as
(
select ROW_NUMBER() over (order by orderdate) as num
, empId
, orderdate
from yourTable
),
dateGroups(groupNum, empId, orderDate, num) as
(
select currD.num, currD.empid, currD.orderDate, currD.num
from dateSequences currD
left join dateSequences prevD on prevD.num = currD.num - 1 and prevD.empid = currD.empId
where prevD.num is null
union all
select dg.groupNum, d.empId, d.orderDate, d.num
from dateSequences d
inner join dateGroups dg on dg.num + 1 = d.num and d.empId = dg.empId
)
select empId, min(orderDate) as MinDate, max(orderDate) as MaxDate
from dateGroups
where empId = 4
group by empId, groupNum
Basically it first makes a CTE to get the row numbers for each row in date order. Then it makes a recursive CTE that first finds all the groups with no previous sequential entries then adds all subsequent entries to the same group. Finally it takes the records with all the group numbers assigned and groups them by their group number and gets the min and max dates.
I have a data looks like this from my database. My report will have 2 parameters, Start Date and End Date.
For example if the user select Start Date = 1/1/2015 and End Date = 12/31/2015, the report should return user TierCode = Privilege.
I've achieve this using Stored Procedure. But the performance is an issues here as I couldn't use Extract Data.
SELECT
m.MemberID,
ty.TierCode AS TierCodeTY,
ly.TierCode AS TierCodeLY
FROM
Tangs_dim_Member m LEFT JOIN
(
SELECT TierCode, MemberID, ROW_NUMBER() OVER(PARTITION BY MemberID ORDER BY SnapshotDate DESC) AS i
FROM dw_Tangs_MonthlySnapshot
WHERE SnapshotDate >= #StartDate AND SnapshotDate <= #EndDate
) ty
ON
ty.MemberID = m.MemberID AND ty.i = 1 LEFT JOIN
(
SELECT TierCode, MemberID, ROW_NUMBER() OVER(PARTITION BY MemberID ORDER BY SnapshotDate DESC) AS i
FROM dw_Tangs_MonthlySnapshot
WHERE SnapshotDate >= DATEADD(year,-1,#StartDate) AND SnapshotDate <= DATEADD(year,-1,#EndDate)
) ly
ON
ly.MemberID = m.MemberID AND ly.i = 1
How can I achieve above report without using Stored Procedure. Calculated field is fine as long I can use Views / Custom Query / Tables + Extract Data. So the data will be filtered at Tableau instead at the database.
I think you can get the last inserted record by adding Ordered by [date]
and get just first one by adding [Limit 1] in the sql query
hope that help you
Is there any way to use ROW_NUMBER() in SQL without using OVER, because I want to use sorting.
I have a Grid with multiple sortable columns with configurable rows. In my scenario order by is variable that's why I am not able to put order by using ROWNUM.
select ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as number from Task order by RuleId
I approached this using a different logic. Instead of checking for every single day and verifying it is a weekday or a holiday I create a table which lists only the business days and then take the nth value.
CREATE OR REPLACE FUNCTION add_n_working_days (
start_date DATE, working_days PLS_INTEGER
) RETURN DATE AS
l_end_date DATE := start_date;
l_counter pls_integer := 0;
BEGIN
SELECT
business_day
INTO l_end_date
FROM
(
WITH
dates AS
(SELECT start_date + level - 1 as dt FROM dual CONNECT BY level < 100)
,weekdates AS
(SELECT dt as weekday FROM dates WHERE TO_CHAR(dt,'fmdy') NOT IN ('sat','sun'))
,business_days AS
(
SELECT weekday as business_day FROM weekdates
MINUS
SELECT holiday FROM so_holidays
)
SELECT business_day, ROW_NUMBER() OVER (ORDER BY 1) as rn from business_days
)
WHERE rn = working_days + 1;
RETURN l_end_date;
END add_n_working_days;
If working_days gets too high then I suggest making that value 100 a variable.
select
a.City,
a.len
from
(
select city,length(city) AS len,
row_number()over(order by length(city) desc, city) as hi,
row_number()over(order by length(city), city) as lo
from
STATION) as a where (a.lo=1 or a.hi=1);
Sorry stuck on this query, since I have the data in the order by clause it tells me I have to put in an aggregate or group by clause? (even if I don't need that aggregate value?).
Table UserData ( userID, sales, credits, dateCreated)
My query has to return the last 10 results:
SELECT TOP 10 COUNT(*) as totalDays, SUM(sales), SUM(credits)
FROM UserData
WHERE userID = #userID
ORDER BY dateCreated DESC
I have totalDays because maybe it won't return the # of days I asked for (in this case it is 10, but it can be changed later).
This gives you the totals for the last 10 days:
SELECT
COUNT(*) as totalDays, SUM(sales), SUM(credits)
FROM
UserData
WHERE
userID = #userID
AND DateCreated > GETDATE() - 10
Last 10 sales
SELECT COUNT(*) as totalDays, SUM(sales), SUM(credits)
FROM
(SELECT TOP 10 sales, credits
FROM UserData
WHERE userID = #userID
ORDER BY dateCreated DESC) X
There is no point in using top or order by on a query that only returns a single row in the result. First you have to make the query return more than one row to make any use of them.
This will simply aggregate all sales and return a single row, so you have to do something to it first:
select count(*) as totalDays, sum(sales), sum(credits)
from UserData
where userID = #userID
If you want to take the last ten sales and sum up, you need a subquery that first isolates the ten sales, then you can aggregate them:
select count(*) as totalDays, sum(sales), sum(credits)
from (
select top 10 sales, credits
from UserData
where userID = #userID
order by dateCreated desc
) LastData
If you want to sum up each day an return the last ten days, you need to group on the date:
select top 10 count(*) as totalDays, sum(sales), sum(credits)
from UserData
where userID = #userID
group by dateCreated
order by dateCreated desc
This is happening because of the * (ALL) field.
Since you aggregating you should pick another field to count, any field would do in your case which would make your query something like this:
SELECT TOP 10 COUNT(USERID) AS TOTALDAYS, SUM(SALES), SUM(CREDITS)
FROM USERDATA
WHERE userid = #userid
GROUP BY datecreated
ORDER BY datecreated DESC
Even though the datecreated isn't used in the SELECT clause, it still needs to be in the GROUP BY portion.
Hope this helps.