Find top sales people - sql-server

I want to find Top and botton 10% sales people.How can I do this using SQL 2005 or 2008?
DECLARE #Sales TABLE
(
SalesPersonID varchar(10), TotalSales int
)
INSERT #Sales
SELECT 1, 200 UNION ALL
SELECT 2, 300 UNION ALL
SELECT 7, 300 UNION ALL
SELECT 4, 100 UNION ALL
SELECT 5, 600 UNION ALL
SELECT 5, 600 UNION ALL
SELECT 2, 200 UNION ALL
SELECT 5, 620 UNION ALL
SELECT 4, 611 UNION ALL
SELECT 3, 650 UNION ALL
SELECT 7, 611 UNION ALL
SELECT 9, 650 UNION ALL
SELECT 3, 555 UNION ALL
SELECT 9, 755 UNION ALL
SELECT 8, 650 UNION ALL
SELECT 3, 620 UNION ALL
SELECT 5, 633 UNION ALL
SELECT 6, 720
GO
Also If i add department, then how can i write same query to find top 10% and bottom 10% in each department? I please want both queries.

TOP 10 %
select top 10 percent SalesPersonID, sum(TotalSales)
from Sales
order by sum(TotalSales)
group by SalesPersonID
BOTTOM 10 %
select top 10 percent SalesPersonID, sum(TotalSales)
from Sales
order by sum(TotalSales) desc
group by SalesPersonID

--Top 10%
SELECT TOP 10 PERCENT SalesPersonID, SUM(TotalSales) FROM #Sales
GROUP BY SalesPersonID
ORDER BY SUM(TotalSales) ASC
--Bottom 10%
SELECT TOP 10 PERCENT SalesPersonID, SUM(TotalSales) FROM #Sales
GROUP BY SalesPersonID
ORDER BY SUM(TotalSales) DESC
If you added a column Department varchar(20) for example:
--By Dept
SELECT TOP 10 PERCENT Department, SUM(TotalSales) FROM #Sales
GROUP BY Department
ORDER BY SUM(TotalSales) ASC/DESC //(Whichever one you want)

cte version:
DECLARE #Sales TABLE (SalesPersonID varchar(10), TotalSales int)INSERT #Sales
SELECT 1, 200 UNION ALL
SELECT 2, 300 UNION ALL
SELECT 7, 300 UNION ALL
SELECT 4, 100 UNION ALL
SELECT 5, 600 UNION ALL
SELECT 5, 600 UNION ALL
SELECT 2, 200 UNION ALL
SELECT 5, 620 UNION ALL
SELECT 4, 611 UNION ALL
SELECT 3, 650 UNION ALL
SELECT 7, 611 UNION ALL
SELECT 9, 650 UNION ALL
SELECT 3, 555 UNION ALL
SELECT 9, 755 UNION ALL
SELECT 8, 650 UNION ALL
SELECT 3, 620 UNION ALL
SELECT 5, 633 UNION ALL
SELECT 6, 720
;with a as
(
select SalesPersonID, sum(TotalSales) as Total
from #Sales
group by SalesPersonID
)
select coalesce(a.SalesPersonID, b.SalesPersonID) as SalesPersonID, coalesce(a.Total,b.Total) as Total
from a a
full outer join a b
on a.SalesPersonID=b.SalesPersonID
where a.SalesPersonID in (select top 10 percent SalesPersonID from a order by Total desc)
or b.SalesPersonID in (select top 10 percent SalesPersonID from a order by Total)
order by a.Total desc

Related

Generating a derived table in SSRS from last purchases in two different SQL Server tables, and then joining with a third

Suppose I have three tables:
one of customer info with a unique ID (CUST_ID)
one of customer pants purchases 3 columns (CUST_ID, PANT_TYPE, PANT_DATE)
one of customer shirts purchases 3 columns (CUST_ID, SHIRT_TYPE, SHIRT_DATE)
Additionally, I wish to exclude certain pant types and certain shirt types (PANT_TYPE IS NOT 'JEANS', SHIRT_TYPE IS NOT 'TUXEDO'), and only grab the most recent pant purchase and shirt purchase.
So, ideally, I would end up with final table like this:
CUST_ID, LAST_PANT_TYPE, LAST_PANT_DATE, LAST_SHIRT_TYPE, LAST_SHIRT_DATE
For four hours at work I tried to get this solution to work, but the 'OVER' statement breaks SSRS and causes problems in testing the query and even drops the fields randomly at times. So, I am thinking derived tables of some sort might work.
I am pretty new to SQL and have learned a lot trying to solve this, but I need to get there STAT.
Using Common Table Expressions for your derived tables, you query could look like this:
WITH
p (cust_id, pant_type, pant_date, rn) AS (
SELECT cust_id, pant_type, pant_date,
ROW_NUMBER() OVER (PARTITION BY cust_id ORDER BY pant_date DESC)
FROM Pants WHERE pant_type NOT IN ('JEANS')
),
s (cust_id, shirt_type, shirt_date, rn) AS (
SELECT cust_id, shirt_type, shirt_date,
ROW_NUMBER() OVER (PARTITION BY cust_id ORDER BY shirt_date DESC)
FROM Shirts WHERE shirt_type NOT IN ('TUXEDO')
)
SELECT c.cust_id,
p.pant_type AS last_pant_type, p.pant_date AS last_pant_date,
s.shirt_type AS last_shirt_type, s.shirt_date AS last_shirt_date
FROM Customers c
LEFT JOIN p ON c.cust_id = p.cust_id AND p.rn = 1
LEFT JOIN s ON c.cust_id = s.cust_id AND s.rn = 1;
You could try using the APPLY operator, e.g.:
SELECT
C.CUST_ID
, PANT.PANT_TYPE LAST_PANT_TYPE
, PANT.PANT_DATE LAST_PANT_DATE
, SHIRT.SHIRT_TYPE LAST_SHIRT_TYPE
, SHIRT.SHIRT_DATE LAST_SHIRT_DATE
FROM
CUSTOMER C
OUTER APPLY
(
SELECT TOP 1
P.PANT_TYPE
, P.PANT_DATE
FROM PANT P
WHERE
P.CUST_ID = C.CUST_ID
AND P.PANT_TYPE <> 'JEANS'
ORDER BY P.PANT_DATE DESC
) PANT
OUTER APPLY
(
SELECT TOP 1
S.SHIRT_TYPE
, S.SHIRT_DATE
FROM SHIRT S
WHERE
S.CUST_ID = C.CUST_ID
AND S.SHIRT_TYPE <> 'TUXEDO'
ORDER BY S.SHIRT_DATE DESC
) SHIRT
Using OUTER APPLY (as opposed to CROSS APPLY) ensures that none of the customers will be filtered out (NULL will be returned in the 'PANT' or 'SHIRT' columns if there is no data for the customer in their respective tables).
I ended up making data and using ROW_NUMBER to identify the last purchase.
SELECT 1 AS CUST_ID
INTO #CUSTOMERS
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
SELECT 1 AS CUST_ID, 'SLACKS' AS PANT_TYPE, CAST('1/1/2017' AS DATE) AS PANT_DATE
INTO #PANTS
UNION
SELECT 1, 'CARGO SHORTS', CAST('2/2/2018' AS DATE)
UNION
SELECT 1, 'SLACKS', CAST('3/3/2018' AS DATE)
UNION
SELECT 2, 'CARGO PANTS', CAST('2/2/2017' AS DATE)
UNION
SELECT 2, 'SLACKS', CAST('4/4/2018' AS DATE)
UNION
SELECT 3, 'CARGO PANTS', CAST('4/1/2018' AS DATE)
UNION
SELECT 3, 'SLACKS', CAST('5/8/2017' AS DATE)
UNION
SELECT 4, 'CARGO SHORTS', CAST('2/2/2018' AS DATE)
UNION
SELECT 4, 'SLACKS', CAST('3/3/2018' AS DATE)
UNION
SELECT 4, 'CARGO PANTS', CAST('2/2/2017' AS DATE)
UNION
SELECT 4, 'SLACKS', CAST('4/4/2018' AS DATE)
UNION
SELECT 4, 'CARGO PANTS', CAST('4/1/2018' AS DATE)
UNION
SELECT 4, 'SLACKS', CAST('5/8/2017' AS DATE)
SELECT 1 AS CUST_ID, 'POLO' AS SHIRT_TYPE, CAST('1/1/2017' AS DATE) AS SHIRT_DATE
INTO #SHIRTS
UNION
SELECT 1, 'POLO - LONG SLEEVE', CAST('2/2/2018' AS DATE)
UNION
SELECT 1, 'POLO - LONG SLEEVE', CAST('3/3/2018' AS DATE)
UNION
SELECT 2, 'POLO', CAST('2/2/2017' AS DATE)
UNION
SELECT 2, 'POLO - LONG SLEEVE', CAST('4/4/2018' AS DATE)
UNION
SELECT 3, 'T-SHIRT', CAST('4/1/2018' AS DATE)
UNION
SELECT 3, 'POLO', CAST('5/8/2017' AS DATE)
UNION
SELECT 4, 'T-SHIRT', CAST('2/2/2018' AS DATE)
UNION
SELECT 4, 'POLO', CAST('3/3/2018' AS DATE)
UNION
SELECT 4, 'T-SHIRT', CAST('2/2/2017' AS DATE)
UNION
SELECT 4, 'POLO - LONG SLEEVE', CAST('4/4/2018' AS DATE)
UNION
SELECT 4, 'T-SHIRT', CAST('4/1/2018' AS DATE)
UNION
SELECT 4, 'POLO', CAST('5/8/2017' AS DATE)
SELECT C.CUST_ID, P.PANT_TYPE, P.PANT_DATE,
S.SHIRT_TYPE, S.SHIRT_DATE
FROM #CUSTOMERS C
LEFT JOIN (SELECT CUST_ID, PANT_TYPE, PANT_DATE, ROW_NUMBER()OVER(PARTITION BY CUST_ID ORDER BY PANT_DATE DESC) AS ROW_NUM FROM #PANTS) P ON P.CUST_ID = C.CUST_ID AND P.ROW_NUM = 1
LEFT JOIN (SELECT CUST_ID, SHIRT_TYPE, SHIRT_DATE, ROW_NUMBER()OVER(PARTITION BY CUST_ID ORDER BY SHIRT_DATE DESC) AS ROW_NUM FROM #SHIRTS) S ON S.CUST_ID = C.CUST_ID AND S.ROW_NUM = 1

Copy previous row value to all next rows in sql

I have requirement to copy previous rows values to next all rows in sql server.
With LAG function, I can achieve this one only for next row. but I have to copy more than rows.
Here is sample example :
Query:
SELECT
t1.ID,
t1.CustID,
t2.ID,
t2.CustID,
t2.Flag,
COALESCE(
t2.Flag,
(
SELECT TOP 1 l.Flag
FROM TBL2 l
WHERE l.CustID = t1.CustID AND l.ID < t1.ID
ORDER BY l.ID desc
)) as 'Final'
FROM
TBL1 t1
LEFT OUTER JOIN TBL2 t2 ON t2.ID = t1.ID AND t2.CustID = t1.CustID
ORDER BY
t1.CustID,
t1.ID desc
Setup:
CREATE TABLE TBL1 (ID int, CustID int)
GO
CREATE TABLE TBL2 (ID int, CustID int, Flag bit)
GO
INSERT INTO TBL1 (ID, CustID)
SELECT 1, 11 UNION ALL
SELECT 1, 12 UNION ALL
SELECT 1, 13 UNION ALL
SELECT 1, 14 UNION ALL
SELECT 1, 15 UNION ALL
SELECT 1, 16 UNION ALL
SELECT 1, 17 UNION ALL
SELECT 2, 11 UNION ALL
SELECT 2, 12 UNION ALL
SELECT 2, 13 UNION ALL
SELECT 2, 14 UNION ALL
SELECT 2, 15 UNION ALL
SELECT 2, 16 UNION ALL
SELECT 2, 17 UNION ALL
SELECT 3, 11 UNION ALL
SELECT 3, 12 UNION ALL
SELECT 3, 13 UNION ALL
SELECT 3, 14 UNION ALL
SELECT 3, 15 UNION ALL
SELECT 3, 16 UNION ALL
SELECT 3, 17 UNION ALL
SELECT 4, 11 UNION ALL
SELECT 4, 12 UNION ALL
SELECT 4, 13 UNION ALL
SELECT 4, 14 UNION ALL
SELECT 4, 15 UNION ALL
SELECT 4, 16 UNION ALL
SELECT 4, 17
GO
INSERT INTO TBL2 (ID, CustID, Flag)
SELECT 1, 11, 0 UNION ALL
SELECT 1, 12, 1 UNION ALL
SELECT 1, 13, 1 UNION ALL
SELECT 1, 14, 0 UNION ALL
SELECT 1, 15, 0 UNION ALL
SELECT 1, 16, 0 UNION ALL
SELECT 1, 17, 1 UNION ALL
SELECT 2, 11, 1 UNION ALL
SELECT 2, 13, 0 UNION ALL
SELECT 2, 14, 1 UNION ALL
SELECT 2, 15, 1 UNION ALL
SELECT 2, 17, 0 UNION ALL
SELECT 3, 13, 1 UNION ALL
SELECT 3, 15, 0 UNION ALL
SELECT 3, 17, 1 UNION ALL
SELECT 4, 12, 0 UNION ALL
SELECT 4, 17, 0
GO
You can try this:
SELECT *
,ISNULL(b.flag,(MAX(b.flag) OVER (PARTITION BY a.[custid] ORDER BY b.[id] DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)))
FROM #TBL1 A
LEFT JOIN #TBL2 B
ON A.id = b.id
AND A.custid = b.custid
ORDER BY a.[custid] ASC, a.[id] DESC
Here is the sample data:
DECLARE #TBL1 TABLE
(
[id] TINYINT
,[custid] TINYINT
);
DECLARE #TBL2 TABLE
(
[id] TINYINT
,[custid] TINYINT
,[flag] TINYINT
);
INSERT INTO #TBL1([id], [custid])
VALUES
(1,11)
,(1,12)
,(1,13)
,(1,14)
,(1,15)
,(1,16)
,(1,17)
,(2,11)
,(2,12)
,(2,13)
,(2,14)
,(2,15)
,(2,16)
,(2,17)
,(3,11)
,(3,12)
,(3,13)
,(3,14)
,(3,15)
,(3,16)
,(3,17)
,(4,11)
,(4,12)
,(4,13)
,(4,14)
,(4,15)
,(4,16)
,(4,17);
INSERT INTO #TBL2 ([id], [custid], [flag])
VALUES (1,11,0)
,(1,12,1)
,(1,13,1)
,(1,14,0)
,(1,15,0)
,(1,16,0)
,(1,17,1)
,(2,11,1)
,(2,13,0)
,(2,14,1)
,(2,15,1)
,(2,17,0)
,(3,13,1)
,(3,15,0)
,(3,17,1)
,(4,12,0)
,(4,17,0)
You can use a LEFT JOIN ,a CASE EXPRESSION and a correlated query :
SELECT t.id,t.custid,s.id,s.custid,
COALESCE(s.flag,(SELECT TOP 1 ss.flag FROM tbl2 ss
WHERE ss.custid = t.custid and ss.id < t.id
ORDER BY ss.id DESC)) as flag
FROM Tbl1 t
LEFT JOIN tbl2 s
ON(t.custid = s.custid and s.id = t.id)

Get contiguous date ranges grouped into a single line

I have a table which holds a lot of rows (Currently, 500K, expected to rise to 15 Million in the next 3 years). The table holds payments made for a certain event for a specific day. And event can have 1 or many payments for the same day, but the payments on the same day must have different PaymentTypes.
Below is a table variable creation that creates the basic data (Input), and then a hardcoded select which is the expected output. I need to group continuous date ranges for a payment type, for a placement, in one row, with a From and To date, and then when there's a break - no rows, and then for the next date range.
For example:
Placement 1 got payments from the 1st to the 2nd (2 days) for Payment type 5, and then from the 4th until the 6th for the same type. Therefore, two rows. Payment type 1 also got a payment for the 1st to the 3rd for payment type 10. So, that is another row.
DECLARE #Temp TABLE
(
Id INT NOT NULL IDENTITY(1,1),
PlacementId INT NOT NULL,
PaymentTypeId INT NOT NULL,
DateValue DATETIME NOT NULL,
Amount DECIMAL(16,2) NOT NULL
)
INSERT INTO #Temp (PlacementId, PaymentTypeId, DateValue, Amount)
SELECT 1, 5, '01-JAN-2015', 100 UNION
SELECT 1, 5, '02-JAN-2015', 150 UNION
SELECT 1, 5, '04-JAN-2015', 78 UNION
SELECT 1, 5, '05-JAN-2015', 89 UNION
SELECT 1, 5, '06-JAN-2015', 22 UNION
SELECT 1, 10, '01-JAN-2015', 10 UNION
SELECT 1, 10, '02-JAN-2015', 10 UNION
SELECT 1, 10, '03-JAN-2015', 15 UNION
SELECT 2, 5, '01-JAN-2015', 200 UNION
SELECT 2, 5, '02-JAN-2015', 5 UNION
SELECT 2, 5, '03-JAN-2015', 50 UNION
SELECT 3, 5, '01-JAN-2015', 80 UNION
SELECT 4, 5, '07-JAN-2015', 100 UNION
SELECT 4, 5, '08-JAN-2015', 12 UNION
SELECT 4, 5, '12-JAN-2015', 66 UNION
SELECT 4, 5, '14-JAN-2015', 4 UNION
SELECT 5, 10, '08-JAN-2015', 10
SELECT * FROM #Temp
SELECT 1 AS PlacementId, 5 AS PaymentTypeId, '2015-01-01' AS FromDate, '2015-01-02' AS ToDate, 250 AS Amount UNION
SELECT 1, 10, '2015-01-01', '2015-01-03', 35 UNION
SELECT 1, 5, '2015-01-04', '2015-01-06', 189 UNION
SELECT 2, 5, '2015-01-01', '2015-01-03', 255 UNION
SELECT 3, 5, '2015-01-01', '2015-01-01', 80 UNION
SELECT 4, 5, '2015-01-07', '2015-01-08', 112 UNION
SELECT 4, 5, '2015-01-12', '2015-01-12', 66 UNION
SELECT 4, 5, '2015-01-14', '2015-01-14', 4 UNION
SELECT 5, 10, '2015-01-08', '2015-01-08', 10
Note, there is a NCI on PlacementID and PaymentTypeID.
We're doing it at the moment with a crazy load of cursors, and are having extreme speed issues. (The 500K lines takes 4 minutes to process).
Is there an efficient method to achieve the desired output?
This is a problem called Grouping Islands of Contiguous Dates. Read this article be Jeff Moden for more info.
SQL Fiddle
;WITH Cte AS(
SELECT *,
RN = DATEADD(DAY, - ROW_NUMBER() OVER(PARTITION BY PlacementId, PaymentTypeId ORDER BY DateValue), DateValue)
FROM #Temp
)
SELECT
PlacementId,
PaymentTypeId,
FromDate = MIN(DateValue),
ToDate = MAX(DateValue),
Amount = SUM(Amount)
FROM Cte
GROUP BY PlacementId, PaymentTypeId, RN
ORDER BY PlacementId, PaymentTypeId, FromDate

Select rows based on every nth interval of time

I have a table with a primary key (bigint), datetime, value, foreignKey to configuration tabel that consists of 100,000's of rows. I want to be able to obtain a row for a variable time interval. For example.
Select Timestamp, value from myTable where configID=3
AND{most recent for 15 min interval}
I have a CTE query that returns multiple rows for the interval interval
WITH Time_Interval(timestamp, value, minutes)
AS
(
Select timestamp, value, DatePart(Minute, Timestamp) from myTable
Where Timestamp >= '12/01/2012' and Timestamp <= 'Jan 10, 2013' and
ConfigID = 435 and (DatePart(Minute, Timestamp) % 15) = 0
)
Select Timestamp, value, minutes from Time_Interval
group by minutes, value, timestamp
order by Timestamp
such as:
2012-12-19 18:15:22.040 6.98 15
2012-12-19 18:15:29.887 6.98 15
2012-12-19 18:15:33.480 7.02 15
2012-12-19 18:15:49.370 7.01 15
2012-12-19 18:30:41.920 6.95 30
2012-12-19 18:30:52.437 6.93 30
2012-12-19 19:15:18.467 7.13 15
2012-12-19 19:15:34.250 7.11 15
2012-12-19 19:15:49.813 7.12 15
But as can be seen there are 4 for the 1st 15 minute interval, 2 for the next interval, etc... Worse,
If no data was obtain at an exact times stamp of 15 minutes, then there will be no value.
What I want is the most recent value for a fifteen minute interval... if if the only data for that intervall occurred at 1 second after the start of the interval.
I was thinking of Lead/over but again... the rows are not orgainzed that way. Primary Key is a bigInt and is a clustered Index. Both the timstamp column and ConfigID columns are Indexed. The above query returns 4583 rows in under a second.
Thanks for any help.
Try this on for size. It will even handle returning one row for instances when you have multiple timestamps for a given interval.
NOTE: This assumes your Bigint PK column is named: idx. Just substitute where you see "idx" if it is not.
;WITH Interval_Helper([minute],minute_group)
AS
(
SELECT 0, 1 UNION SELECT 1, 1 UNION SELECT 2, 1 UNION SELECT 3, 1 UNION SELECT 4, 1
UNION SELECT 5, 1 UNION SELECT 6, 1 UNION SELECT 7, 1 UNION SELECT 8, 1 UNION SELECT 9, 1
UNION SELECT 10, 1 UNION SELECT 11, 1 UNION SELECT 12, 1 UNION SELECT 13, 1 UNION SELECT 14, 1
UNION SELECT 15, 2 UNION SELECT 16, 2 UNION SELECT 17, 2 UNION SELECT 18, 2 UNION SELECT 19, 2
UNION SELECT 20, 2 UNION SELECT 21, 2 UNION SELECT 22, 2 UNION SELECT 23, 2 UNION SELECT 24, 2
UNION SELECT 25, 2 UNION SELECT 26, 2 UNION SELECT 27, 2 UNION SELECT 28, 2 UNION SELECT 29, 2
UNION SELECT 30, 3 UNION SELECT 31, 3 UNION SELECT 32, 3 UNION SELECT 33, 3 UNION SELECT 34, 3
UNION SELECT 35, 3 UNION SELECT 36, 3 UNION SELECT 37, 3 UNION SELECT 38, 3 UNION SELECT 39, 3
UNION SELECT 40, 3 UNION SELECT 41, 3 UNION SELECT 42, 3 UNION SELECT 43, 3 UNION SELECT 44, 3
UNION SELECT 45, 4 UNION SELECT 46, 4 UNION SELECT 47, 4 UNION SELECT 48, 4 UNION SELECT 49, 4
UNION SELECT 50, 4 UNION SELECT 51, 4 UNION SELECT 52, 4 UNION SELECT 53, 4 UNION SELECT 54, 4
UNION SELECT 55, 4 UNION SELECT 56, 4 UNION SELECT 57, 4 UNION SELECT 58, 4 UNION SELECT 59, 4
)
,Time_Interval([timestamp], value, [date], [hour], minute_group)
AS
(
SELECT A.[Timestamp]
,A.value
,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101))
,DATEPART(HOUR, A.[Timestamp])
,B.minute_group
FROM myTable A
JOIN Interval_Helper B
ON (DATEPART(minute, A.[Timestamp])) = B.[minute]
AND A.[Timestamp] >= '12/01/2012'
AND A.[Timestamp] <= '01/10/2013'
AND A.ConfigID = 435
)
,Time_Interval_TimeGroup([date], [hour], [minute], MaxTimestamp)
AS
(
SELECT [date]
,[hour]
,minute_group
,MAX([Timestamp]) as MaxTimestamp
FROM Time_Interval
GROUP BY [date]
,[hour]
,minute_group
)
,Time_Interval_TimeGroup_Latest(MaxTimestamp, MaxIdx)
AS
(
SELECT MaxTimestamp
,MAX(idx) as MaxIdx
FROM myTable A
JOIN Time_Interval_TimeGroup B
ON A.[Timestamp] = B.MaxTimestamp
GROUP BY MaxTimestamp
)
SELECT A.*
FROM myTable A
JOIN Time_Interval_TimeGroup_Latest B
ON A.idx = B.MaxIdx
ORDER BY A.[timestamp]
This is another take on the clever time group function from #MntManChris below:
CREATE FUNCTION dbo.fGetTimeGroup (#DatePart tinyint, #Date datetime)
RETURNS int
AS
BEGIN
RETURN CASE #DatePart
WHEN 1 THEN DATEPART(mi, #Date)
WHEN 2 THEN DATEPART(mi, #Date)/5 + 1 -- 5 min
WHEN 3 THEN DATEPART(mi, #Date)/15 + 1 -- 15 min
WHEN 4 THEN DATEPART(mi, #Date)/30 + 1 -- 30 min
WHEN 5 THEN DATEPART(hh, #Date) -- hr
WHEN 6 THEN DATEPART(hh, #Date)/6 + 1 -- 6 hours
WHEN 7 THEN DATEPART(hh, #Date)/12 + 1 -- 12 hours
WHEN 8 THEN DATEPART(d, #Date) -- day
ELSE -1
END
END
If you want to partition in 15 minute interval use datediff in minutes and divide by 15.
And use that partition to rank each interval.
WITH myTbl AS
(
SELECT
timestamp, value,
RANK() OVER (PARTITION BY (DATEDIFF(Mi,0, Timestamp)/15) ORDER BY Timestamp desc) RK
FROM myTable
--WHERE Timestamp BETWEEN '' AND ''
)
SELECT * FROM myTble
WHERE RK <= 1
As my comment above says I've used Rob's answer but implmented a user function to eliminate the Interval_Helper table and the first join. Here is the code for the user function.
BEGIN
DECLARE #Ans integer
if #DatePart = 1 -- min
return DATEPART(mi, #Date)
if #DatePart = 2 -- 5 min
return DatePart(mi,#Date)/5 + 1
if #DatePart = 3 -- 15 min
return DatePart(mi,#Date)/15 + 1
if #DatePart = 4 -- 30min
return DatePart(mi,#Date)/30 + 1
if #DatePart = 5 -- hr
return DATEPART(hh, #Date)
if #DatePart = 6 -- 6 hours
return DATEPART(hh, #Date)/6 + 1
if #DatePart = 7 -- 12 hours
return DATEPART(hh, #Date)/12 + 1
if #DatePart = 8 -- day
return DATEPART(d, #Date)
return -1
END
This then made the Time_Interval table look like
;WITH Time_Interval([timestamp], value, [date], [day], time_group)
AS
(
SELECT A.[Timestamp]
,A.value
,CONVERT(smalldatetime, CONVERT(char(10), A.[Timestamp], 101))
,DATEPART(dd, A.[Timestamp])
,dbo.fGetTimeGroup(#tInterval, A.[Timestamp]) as 'time_group'
FROM myTable A
where
A.[Timestamp] >= '12/01/2012'
AND A.[Timestamp] <= '01/10/2013'
AND A.ConfigID= 435
)
Since there is a switch from "hours" to "days" as the #TimeInterval goes from 1hr to 6hr, or 12hr or every day. I also had to have the Time_Interval_TimeGroup table switch from grouping by [hour] to grouping by [day] and of course having this in the select list.
Since this is part of a much larger abstract DB schema where both the table in question and the db are functions of the ConfigID and thus required dynamic SQL, implmenting this switch in grouping was not an issue, I simply implmented two different dynSql sections based on the value of #TimeInterval
Thanks

a SQL query for sum of all the values of a column

i want a sql query the result like the below :
LineNumber UnitPrice Quantity
1 14 12
2 09 10
3 34 5
4 18 9
5 42 40
6 07 10
7 45 15
-----
101
pls help me....
Another way
WITH YourTable(LineNumber, UnitPrice, Quantity)
AS (SELECT 1, 14,12
UNION ALL
SELECT 2, 09, 10
UNION ALL
SELECT 3, 34, 5
UNION ALL
SELECT 4, 18, 9
UNION ALL
SELECT 5, 42, 40
UNION ALL
SELECT 6, 07, 10
UNION ALL
SELECT 7, 45, 15)
SELECT LineNumber,
UnitPrice,
SUM(Quantity) AS Quantity
FROM YourTable
GROUP BY GROUPING SETS ( ( LineNumber, UnitPrice, Quantity ), ( ) )
To get the total you will use an aggregate:
select sum(quantity) Total
from yourtable
To return the data from your table:
select LineNumber, UnitPrice, Quantity
from yourTable
To return them together you can use a UNION ALL:
select LineNumber, UnitPrice, Quantity
from yourTable
UNION ALL
select 0, 0, sum(quantity) Total
from yourtable
See SQL Fiddle with Demo
-- For all the data from the table
SELECT [LineNumber], [UnitPrice], [Quantity] FROM [SomeTable]
-- For the sum of the quantity field.
SELECT SUM([Quantity]) AS [Sum] FROM [SomeTable]

Resources