Uninterrupted occurrences of weekly events - sql-server

declare #t table([CH_FMT_ID] nvarchar(3),[CH_ISS_DT] date,[CH_RANK] int,[CH_TTL_ID] bigint)
INSERT INTO #t values
('HSI', '6/15/2002', 28, 397130),
('HSI', '6/8/2002', 24, 397130),
('HSI', '6/1/2002', 23, 397130),
('HSI', '5/25/2002', 20, 397130),
('HSI', '5/18/2002', 13, 397130),
('HSI', '5/11/2002', 12, 397130),
('HSI', '5/4/2002', 11, 397130),
('HSI', '6/15/2002', 28 , 111111),
('HSI', '6/8/2002', 24 , 111111),
('HSI', '6/1/2002', 23 , 111111),
('HSI', '5/25/2002', 20 , 111111),
('HSI', '5/18/2002', 13 , 111111),
('HSI', '5/11/2011', 12 , 111111),
('HSI', '5/4/2011', 11 , 111111);
SELECT chart.CH_TTL_ID
,chart.[CH_FMT_ID] Chart
,min(chart.[CH_RANK]) Peak
,max(chart.[CH_RANK]) Trough
,count(chart.[CH_RANK]) Weeks
,MIN(chart.CH_ISS_DT) EntryDate
,MAX(chart.CH_ISS_DT) ExitDate
,(DATEDIFF(day, MIN(CH_ISS_DT),MAX(CH_ISS_DT)) / 7) Weeks_Charted
FROM #t chart
group by chart.CH_TTL_ID
,chart.[CH_FMT_ID]
order by Weeks_Charted desc
The CH_ISS_DT is a date which is updated 1x / week. So the dates are 2017-12-31,2017-12-24, 2017-12-17, etc. The problem comes with the Weeks_Charted column. If something happens the first time in 2007 and doesn't happen again until 2017, the Weeks_Charted will count all weeks in between, even when the data is not present all the time.
This sample returns:
CH_TTL_ID,Chart,Peak,Trough,Weeks,EntryDate,ExitDate,Weeks_Charted
111111,HSI,11,28,7,2002-05-18,2011-05-11,468
397130,HSI,11,28,7,2002-05-04,2002-06-15,6
I am indifferent if the CH_TTL_ID returns 2 rows, one with a 2 as weeks_charted and the other with a 5, or just returns the 2 for the most recent data and the max, mins are different.

Try this query. Query groups by continuous weeks.
select
CH_TTL_ID, CH_FMT_ID Chart
,min([CH_RANK]) Peak
,max([CH_RANK]) Trough
,count([CH_RANK]) Weeks
,MIN(CH_ISS_DT) EntryDate
,MAX(CH_ISS_DT) ExitDate
from (
select
*, sum(N) over (partition by CH_TTL_ID order by CH_ISS_DT) grp
from (
select
*, iif(datediff(dd, lag(CH_ISS_DT) over (partition by CH_TTL_ID order by CH_ISS_DT), CH_ISS_DT) = 7, 0, 1) N
from
#t chart
) t
) t
group by CH_TTL_ID, CH_FMT_ID, grp
One option is to use Recursive CTE in SQL 2008 for this kind of problems
;with cte as (
select
*,row_number() over (partition by CH_TTL_ID, CH_FMT_ID order by CH_ISS_DT) rn
from
#t chart
)
, rcte as (
select
*, 1 grp
from
cte
where
rn = 1
union all
select
a.CH_FMT_ID, b.CH_ISS_DT, b.CH_RANK, a.CH_TTL_ID, b.rn, a.grp + case when datediff(dd, a.CH_ISS_DT, b.CH_ISS_DT) = 7 then 0 else 1 end
from
rcte a
join cte b on a.CH_FMT_ID = b.CH_FMT_ID and a.CH_TTL_ID = b.CH_TTL_ID and a.rn + 1 = b.rn
)
select
CH_TTL_ID, CH_FMT_ID Chart
,min([CH_RANK]) Peak
,max([CH_RANK]) Trough
,count([CH_RANK]) Weeks
,MIN(CH_ISS_DT) EntryDate
,MAX(CH_ISS_DT) ExitDate
from
rcte
group by CH_TTL_ID, CH_FMT_ID, grp
order by CH_FMT_ID, CH_TTL_ID
option (maxrecursion 0)

Related

Extracting a (sampled) time series from an SQL DB

I have an MS SQL data base which contains values stored with their time stamps. So my result table looks like this:
date value
03.01.2016 11
19.01.2016 22
29.01.2016 33
17.02.2016 44
01.03.2016 55
06.03.2016 66
The time stamps don't really follow much of a pattern. Now, I need to extract weekly data from this: (sampled on Friday, for example)
date value
01.01.2016 11 // friday
08.01.2016 11 // next friday
15.01.2016 11
22.01.2016 22
29.01.2016 33
05.02.2016 33
12.02.2016 33
19.02.2016 44
26.02.2016 44
04.03.2016 55
11.03.2016 66
Is there a reasonable way to do this directly in T-SQL?
I could reformat the result table using a C# or Matlab program, but it seems a bit weird, because I seem to again query the result table...
You Could possibly use a CROSS JOIN or INNER JOIN. I would personally go with the INNER JOIN as its much more efficient.
SAMPLE DATA:
CREATE TABLE #Temp(SomeDate DATE
, SomeValue VARCHAR(10));
INSERT INTO #Temp(SomeDate
, SomeValue)
VALUES
('20160103'
, 11),
('20160119'
, 22),
('20160129'
, 33),
('20160217'
, 44),
('20160301'
, 55),
('20160306'
, 66)
QUERY USING CROSS JOIN:
;WITH T
AS (SELECT *
FROM #Temp),
D
AS (
SELECT SomeDate
, SomeValue
FROM #Temp AS A
UNION
SELECT DATEADD(day, 7, SomeDate)
, SomeValue
FROM #Temp AS B
UNION
SELECT DATEADD(day, 14, SomeDate)
, SomeValue
FROM #Temp AS C)
SELECT D.*
FROM T
CROSS JOIN D
WHERE T.SomeValue = D.SomeValue
ORDER BY SomeValue
, SomeDate;
RESULT:
QUERY USING INNER JOIN:
;WITH T
AS (SELECT *
FROM #Temp),
D
AS (
SELECT SomeDate
, SomeValue
FROM #Temp AS A
UNION
SELECT DATEADD(day, 7, SomeDate)
, SomeValue
FROM #Temp AS B
UNION
SELECT DATEADD(day, 14, SomeDate)
, SomeValue
FROM #Temp AS C)
SELECT D.*
FROM T
INNER JOIN D
ON T.SomeValue = D.SomeValue
ORDER BY SomeValue
, SomeDate;
RESULT:
This solution supports a maximum time window of 252 weeks from the first value time.
First row of your desired output is missing, because that friday is before the first value.
If needed, you can add it by mean of a UNION with a min of the table.
DECLARE #tbl TABLE ( [date] date, [value] int )
INSERT INTO #tbl
VALUES
('2016-01-03','11'),
('2016-01-19','22'),
('2016-01-29','33'),
('2016-02-17','44'),
('2016-03-01','55'),
('2016-03-06','66')
;WITH DATA
AS (
SELECT (S+P+Q) WeekNum, DATEADD( week, S + P + Q, MinDate ) Fridays, SubFri, [value]
FROM ( SELECT 1 S UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 ) A
CROSS JOIN ( SELECT 0 P UNION SELECT 7 UNION SELECT 14 UNION SELECT 21 UNION SELECT 28 UNION SELECT 35 ) B
CROSS JOIN ( SELECT 0 Q UNION SELECT 42 UNION SELECT 84 UNION SELECT 126 UNION SELECT 168 UNION SELECT 210 ) C
CROSS JOIN (
SELECT
min ( DATEADD( day, -8 - DATEPART(weekday,[date]), [date] ) ) MinDate,
max ( DATEADD( day, 13 - DATEPART(weekday,[date]), [date] ) ) MaxDate
FROM #tbl
) MD
LEFT JOIN ( SELECT DATEADD( day, 6 - DATEPART(weekday,[date]), [date] ) SubFri, [value] FROM #tbl ) Val
ON SubFri<=DATEADD( week, S + P + Q, MinDate )
WHERE DATEADD( week, S + P + Q, MinDate )<=MaxDate
)
SELECT DATA.Fridays, DATA.value
FROM DATA
INNER JOIN
(
SELECT Fridays, max(SubFri) MaxSubFri
FROM DATA
GROUP BY Fridays
) idx
ON DATA.Fridays=idx.Fridays
AND SubFri=MaxSubFri
ORDER BY Fridays
You should be able to use DATENAME to get all the records of a certain day:
SELECT *
FROM table
WHERE DATENAME(WEEKDAY, date) = 'Friday'
This causes a scan in the query plan though so it would be advisable to have another column with the day of the week and you could just select WHERE dayOfWeekCol = 'Friday'
I found my own solution, which I find more readable. I'm first using a WHILE loop to generate the dates I'm looking for. Then I 'join' these dates to the actual data table using an OUTER APPLY, which looks up 'last value before a specific date'. Here's the code:
-- prepare in-memory table
declare #tbl table ( [date] date, [value] int )
insert into #tbl
values
('2016-01-03','11'),
('2016-01-19','22'),
('2016-01-29','33'),
('2016-02-17','44'),
('2016-03-01','55'),
('2016-03-06','66')
-- query
declare #startDate date='2016-01-01';
declare #endDate date='2016-03-31';
with Fridays as (
select #startDate as fridayDate
union all
select dateadd(day,7,fridayDate) from Fridays where dateadd(day,7,fridayDate)<=#endDate
)
select *
from
Fridays f
outer apply (
select top(1) * from #tbl t
where f.fridayDate >= t.[date]
order by t.[value] desc
) as result
option (maxrecursion 10000)
Gives me:
fridayDate date value
---------- ---------- -----------
2016-01-01 NULL NULL
2016-01-08 2016-01-03 11
2016-01-15 2016-01-03 11
2016-01-22 2016-01-19 22
2016-01-29 2016-01-29 33
2016-02-05 2016-01-29 33
2016-02-12 2016-01-29 33
2016-02-19 2016-02-17 44
2016-02-26 2016-02-17 44
2016-03-04 2016-03-01 55
2016-03-11 2016-03-06 66
2016-03-18 2016-03-06 66
2016-03-25 2016-03-06 66
Thanks for everybody's ideas and support though!

TSQL - Missing Month

I need to find the missing months in a table
for the earliest and latest start dates per ID_No. As an example:
create table #InputTable (ID_No int ,OccurMonth datetime)
insert into #InputTable (ID_No,OccurMonth)
select 10, '2007-11-01' Union all
select 10, '2007-12-01' Union all
select 10, '2008-01-01' Union all
select 20, '2009-01-01' Union all
select 20, '2009-02-01' Union all
select 20, '2009-04-01' Union all
select 30, '2010-05-01' Union all
select 30, '2010-08-01' Union all
select 30, '2010-09-01' Union all
select 40, '2008-03-01'
For the above table, the answer should be:
ID_No OccurMonth
----- ----------
20 2009-02-01
30 2010-06-01
30 2010-07-01
The other solutions posted on this site are similar, but:
1) don't include an ID column,
2) don't use the start date/end dates in the data or
3) use cursors, which are forbidden in my environment.
Try this:
;WITH
MonthRange AS
(
SELECT ID_No,
MinMonth = MIN(OccurMonth),
MaxMonth = MAX(OccurMonth)
FROM #InputTable
GROUP BY ID_No
),
AllMonths AS
(
SELECT ID_No,
OccurMonth = MinMonth
FROM MonthRange
UNION ALL
SELECT a.ID_No,
DATEADD(MONTH, 1, a.OccurMonth)
FROM AllMonths a
INNER JOIN MonthRange r ON a.ID_No = r.ID_No
WHERE a.OccurMonth < r.MaxMonth
)
SELECT a.*
FROM AllMonths a
LEFT JOIN #InputTable i ON a.ID_No = i.ID_No
AND a.OccurMonth = i.OccurMonth
WHERE i.ID_No IS NULL
OPTION (MAXRECURSION 0)
AllMonths is a recursive CTE that lists out all months between the min and max month for each ID_no. Then it's only a simple LEFT JOIN to find what month is missing in between.

SQL Server: Gap / Island, 365 day "contiguous" block

I have a table that looks like this:-
tblMeterReadings
id meter date total
1 1 03/01/2014 100.1
1 1 04/01/2014 184.1
1 1 05/01/2014 134.1
1 1 06/01/2014 132.1
1 1 07/01/2014 126.1
1 1 08/01/2014 190.1
This is an 8 day "contiguous block" from '2014-01-03' to '2014-01-08'.
In the real table there are "contiguous blocks" of years in length.
I need to select the MOST RESCENT CONTINUOUS 365 DAY BLOCK (filtered by meter column). If 365 cannot be found, then it should select next largest continuous block.
When I say CONTINUOUS I mean there must be no days missing.
This is beyond me, so if someone can solve... I will be very impressed.
using distinct to not count days with 2 sets of data
declare #gapdays int = 2 -- replace this with 365 in your case
;with x as
(
select datediff(d, '2014-01-01', [date])-dense_rank()over(order by [date]) grp
,[date]
from #t
)
select top 1 max([date]) last_date, min([date]) first_date, count(distinct [date]) days_in_a_row
from x
group by grp
having count(distinct [date]) >= #gapdays
order by max([date]) desc
There you go:
declare #tblMeterReadings table (id int, meter int, [date] date, total money)
insert into #tblMeterReadings ( id, meter, date, total )
values
(1, 1, '03/01/2014', 100.1),
(1, 1, '04/01/2014', 184.1),
(1, 1, '05/01/2014', 134.1),
(1, 1, '06/01/2014', 132.1),
(1, 1, '07/01/2014', 126.1),
(1, 1, '08/01/2014', 190.1),
(1, 1, '10/01/2014', 200.1),
(1, 1, '12/01/2014', 202.1),
(1, 1, '13/01/2014', 204.1)
;with data as (
select i = datediff(day, '2014', [date]), *
from #tblMeterReadings l
)
, islands as (
select island = l.i - row_number() over (order by i), l.*
from data l
)
, spans as (
select l = min(i), r = max(i)
from islands i
group by island
)
select *
from spans s
left join data l on s.l = l.i
left join data r on s.r = r.i
Most recent continuous block not exceeding 365 days in length will be as follows:
select top 1 *
from spans s
left join data l on s.l = l.i
left join data r on s.r = r.i
where s.l - s.r < 365
order by s.l - s.r desc, s.r desc
With recursive CTE and datepart(dayofyear, date):
with cte as
(
select id, meter, date, datepart(dayofyear, date) as x, cast(1 as int) as level, t1.date as startDate from tblMeterReadings t1
where meter = 1
and not exists(select * from tblMeterReadings t2 where (datepart(dayofyear, t1.date) - 1) = datepart(dayofyear, t2.date))
union all
select t1.id, t1.meter, t1.date, datepart(dayofyear, t1.date) as x, t2.level + 1, t2.startDate from tblMeterReadings t1
inner join cte t2 ON (datepart(dayofyear, t1.date)) = (datepart(dayofyear, t2.date) + 1)
)
select TOP 365 * from cte
where cte.startDate = (select top 1 startdate
from cte
--where Level <= 365
order by Level desc, startDate desc)
order by Level desc
OPTION ( MAXRECURSION 365 )
SQL Fiddle example

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