Alternative LAG function in SQL Server 2005 - tsql

Maybe somebody could help me. I am using SQL Server 2005 and I can't use the lag function.
I have a table:
2014-02-03 07:42:00.000
2014-02-03 18:49:00.000
2014-02-06 14:54:00.000
2014-02-07 17:58:00.000
2014-02-20 13:39:00.000
How I can get this result:
2014-02-03 07:42:00.000 NULL
2014-02-03 18:49:00.000 2014-02-03 07:42:00.000
2014-02-06 14:54:00.000 2014-02-03 18:49:00.000
2014-02-07 17:58:00.000 2014-02-06 14:54:00.000
2014-02-20 13:39:00.000 2014-02-07 17:58:00.000

suppose your table is called dt and the colum x then:
select x,(select max(x) from dt d2 where d2.x<d1.x) from dt d1

this ill work even in SQL Server 7!
fiddle
select min(date),null from datetable
union
select t1.date, max(t2.date)
from dateTable t1
join dateTable t2 on t2.date < t1.date
group by t1.date

Related

Why is this nested INNER JOIN not working in POSTGRESQL?

I am using the Nothwind data base & working in pgAdmin, and my query is looking like this at the moment
SELECT
TO_CHAR (o.ShippedDate, 'yyyy.MM') AS Month
,o.OrderID
,Total
,SUM (Total) OVER PARTITION BY TO_CHAR (ShippedDate,
‘yyyy.MM’) ORDER BY O.OrderID) AS Running_Total
FROM public.orders O
INNER JOIN (
SELECT OrderID, SUM(Quantity*UnitPrice) AS Total
FROM public.order_details
GROUP BY OrderID
ORDER BY OrderID
) OD ON O.OrderID = OD.OrderID
WHERE
TO_CHAR (o.ShippedDate, 'yyyy.MM') IS NOT NULL
And is is not working, it says:
ERROR: column "o.shippeddate" must appear in the GROUP BY clause or be used in an aggregate function
LINE 2: TO_CHAR (o.ShippedDate, 'yyyy.MM') AS Month
Can you help me out what could be the issue? Thanks!
I fixed the query, so it is now the correct one.

SQL 2008 cumulative count

I have a query returning the number of rows grouped by date :
SELECT convert(date, run.TimeStamp) as TimeStamp, count(*)
FROM ScriptResult AS res INNER JOIN
ScriptRun AS run ON run.ScriptRunID = res.ScriptRunID INNER JOIN
WorkListItems AS wli ON wli.WorkListItemID = res.WorklistItemID INNER JOIN
WorkList AS wl ON wl.WorkListID = wli.WorkListID
WHERE (wli.WorkListID = #WLID)
GROUP by convert(date, run.TimeStamp)
ORDER BY convert(date, run.TimeStamp);
This produces a result set like this :
TimeStamp (ItemCount)
2015-03-10 5364
2015-03-11 22027
2015-03-12 18037
Now what I want, is to cumulatively summarize the itemcount, like this :
TimeStamp ItemCount TotalCount
2015-03-10 5364 5364
2015 -03-11 22027 27391
2015-03-12 18037 45428
The query needs to be compatible with 2008R2.
I have played with [count ...over..partition by] in several variations but the problem is that the window function boundary should chage. And I cannot use ROWS or RANGE.
Any ideas please ?
Thanks in advance.
Try with correlated subquery:
;WITH cte as(
SELECT convert(date, run.TimeStamp) as TimeStamp, count(*) AS S
FROM ScriptResult AS res INNER JOIN
ScriptRun AS run ON run.ScriptRunID = res.ScriptRunID INNER JOIN
WorkListItems AS wli ON wli.WorkListItemID = res.WorklistItemID INNER JOIN
WorkList AS wl ON wl.WorkListID = wli.WorkListID
WHERE (wli.WorkListID = #WLID)
GROUP by convert(date, run.TimeStamp)
)
SELECT TimeStamp,
S,
(SELECT SUM(S) FROM cte t2 WHERE t2.TimeStamp <= t1.TimeStamp) AS TS
FROM cte t1
You could try creating a temp table to hold the first query results that you can further aggregate to return the cumulative sum on the ItemCount field:
CREATE TABLE #TempTable(
[SeqNo] [int] NULL,
[TimeStamp] [Date] NULL,
[ItemCount] [int] NULL
) ON [PRIMARY]
SELECT
ROW_NUMBER() OVER (PARTITION BY res.ScriptRunID ORDER BY run.TimeStamp) AS SeqNo,
CONVERT(Date, run.TimeStamp) AS TimeStamp,
COUNT(*) AS ItemCount
INTO #TempTable
FROM ScriptResult AS res
INNER JOIN ScriptRun AS run
ON run.ScriptRunID = res.ScriptRunID
INNER JOIN WorkListItems AS wli
ON wli.WorkListItemID = res.WorklistItemID
INNER JOIN WorkList AS wl
ON wl.WorkListID = wli.WorkListID
WHERE (wli.WorkListID = #WLID)
GROUP BY CONVERT(Date, run.TimeStamp)
ORDER BY CONVERT(Date, run.TimeStamp);
SELECT
t1.TimeStamp,
t1.ItemCount,
SUM(t2.ItemCount) AS TotalCount
FROM #TempTable AS t1
INNER JOIN #TempTable AS t2
on t1.SeqNo >= t2.SeqNo
GROUP BY t1.TimeStamp, t1.ItemCount
ORDER BY t1.TimeStamp
SQL Fiddle Example
Note: This links to a Microsoft SQL Server 2014 database version SQL fiddle which should work with SQL Server 2008 as well.

How to write a T-SQL query to select top 1 records for each client?

I have a simple script that I am trying to get the most recent records per client on. How do I do this in TSQL? This is my code currently, however, this is only selecting one record total. This one record displays most recent record for ALL clients and not EACH client! How can I reformulate this please?
SELECT TOP 1
C.ClientID, actual_date
From ClientRecords C
WHERE (#ClientID is NULL or C.Client_ID = #ClientID)
Group by C.ClientID, actual_date
ORDER BY C.actual_date
Aggregate the column by using MAX() function on actual_date
SELECT C.ClientID, MAX(actual_date) max_DATE
From ClientRecords C
WHERE (#ClientID is NULL or C.Client_ID = #ClientID)
Group by C.ClientID
ORDER BY C.actual_date
This has not been tested, but it should look something like:
select
c.clientId, max(actual_date) as Actual_date
from clientrecords C
group by c.clientID
order by c.clientID
That will give you the highest actual date for each client, ordered by the clientId.
Thanks guys, but I found a little more satisfactory solutoin to this:
WITH rs AS
(
SELECT
C.ClientID, actual_date,ROW_NUMBER() OVER(ORDER BY C.ClientID, actual_date)rid
From ClientRecords C
)
SELECT * FROM rs WHERE rid =1
You can use SUBQUERY for that purpose:
SELECT
C.ClientID ,
(SELECT MAX(C1.actual_date) FROM ClientRecords C1 WHERE C1.Client_ID = C.Client_ID) AS MaxDate
FROM ClientRecords C
WHERE (#ClientID is NULL or C.Client_ID = #ClientID)
Group by C.ClientID, actual_date
ORDER BY C.actual_date

Aggregates in Visual Studio Reports not showing

I'm trying to create a report that UNIONs two datasets. It takes (1) a bunch of orders for a specific customer within a date range, and UNIONs it with (headers and) (2) the method of shipping following by the average of the time interval between the order being placed and the order being sent.
The screenshot below shows that, in SQL Server, the query works perfectly. However, when I run this exact same query in Visual Studio 2008 to create a report for this, the actual value of the average turnaround time is empty.
As far as I can tell, in SQL Server the query works perfectly for whatever parameters I give it. I just can't figure out why in the report the average turnaround time is always blank.
The query I'm running is:
DECLARE #turnaroundInfo TABLE
(
[Owner Reference] VARCHAR(48),
[Project] VARCHAR(48),
[Carrier Type] VARCHAR(48),
[Created Date] DATETIME,
[Shipped Date] DATETIME,
[Turnaround Time (hours)] INT
)
INSERT INTO #turnaroundInfo
SELECT orders.ownerReference AS [Owner Reference], p.name AS [Project], types.name AS [Carrier Type], orders.createdSysDateTime AS [Created Date], shipments.shippedDate AS [Shipped Date], DATEDIFF(HOUR, orders.createdSysDateTime, shipments.shippedDate) AS [Turnaround Time (hours)]
FROM datex_footprint.Orders orders
INNER JOIN datex_footprint.Projects p ON orders.projectId = p.id
INNER JOIN datex_footprint.CarrierServiceTypes types ON orders.preferredCarrierServiceTypeId = types.id
INNER JOIN datex_footprint.OrderLines lines ON orders.id = lines.orderId
INNER JOIN datex_footprint.Shipments shipments ON lines.shipmentId = shipments.id
WHERE p.name IN (#project) AND types.name IN(#carrier)
-- Get only the type and date-ranged turnaround info we want
DECLARE #orders TABLE
(
[Owner Reference] VARCHAR(48),
[Project] VARCHAR(48),
[Carrier Type] VARCHAR(48),
[Created Date] DATETIME,
[Shipped Date] DATETIME,
[Turnaround Time (hours)] INT
)
INSERT INTO #orders
SELECT *
FROM #turnaroundInfo
WHERE [Turnaround Time (hours)] >= 0 AND [Created Date] BETWEEN #startDate AND #endDate
ORDER BY [Turnaround Time (hours)], [Carrier Type] ;
-- UNION the relevant turnaround infor with headers
SELECT * FROM #orders o /* All the orders in the date range for this project and the selected carrier(s) */
UNION ALL
SELECT 'Carrier' AS [Carrier Type], 'Avg Turnaround Time' AS [Average Turnaround], NULL AS Column3, NULL AS Column4, NULL AS Colummn5, NULL AS Column6
UNION ALL
SELECT o.[Carrier Type], CAST(AVG(o.[Turnaround Time (hours)]) AS NVARCHAR(24)) AS [Average Turnaround], NULL AS Column3, NULL AS Column4, NULL AS Colummn5, NULL AS Column6
FROM #orders o
GROUP BY o.[Carrier Type];
Does anybody know or see what I might be missing?
Any help would be appreciated!
It's not blank, it's just might not in the column you expected - I can see the value '24' in your screenshot.
I figured out what my mistake was.
The column about the value 24 and the header and 24 value column were sized differently. In SQL Server, it didn't seem to care, but in Visual Studio it saw the size difference and actually dropped the whole column from displaying.
After I adjusted the average value column to VARCHAR(48), which is what the column above it was sized to, it displayed properly again.

TSQL invalid HAVING count

I am using SSMS 2008 and trying to use a HAVING statement. This should be a real simple query. However, I am only getting one record returned event though there are numerous duplicates.
Am I doing something wrong with the HAVING statement here? Or is there some other function that I could use instead?
select
address_desc,
people_id
from
dbo.address_view
where people_id is not NULL
group by people_id , address_desc
having count(*) > 1
sample data from address_view:
people_id address_desc
---------- ------------
Murfreesboro, TN 37130 F15D1135-9947-4F66-B778-00E43EC44B9E
11 Mohawk Rd., Burlington, MA 01803 C561918F-C2E9-4507-BD7C-00FB688D2D6E
Unknown, UN 00000 C561918F-C2E9-4507-BD7C-00FB688D2D6E
Jacksonville, NC 28546 FC7C78CD-8AEA-4C8E-B93D-010BF8E4176D
Memphis, TN 38133 8ED8C601-5D35-4EB7-9217-012905D6E9F1
44 Maverick St., Fitchburg, MA 8ED8C601-5D35-4EB7-9217-012905D6E9F1
The GROUP BY is going to lump your duplicates together into a single row.
I think instead, you want to find all people_id values with duplicate address_desc:
SELECT a.address_desc, a.people_id
FROM dbo.address_view a
INNER JOIN (SELECT address_desc
FROM dbo.address_view
GROUP BY address_desc
HAVING COUNT(*) > 1) t
ON a.address_desc = t.address_desc
using row_number and partition you can find the duplicate occurrences where row_num>1
select address_desc,
people_id,
row_num
from
(
select
address_desc,
people_id,
row_number() over (partition by address_desc order by address_desc) row_num
from
dbo.address_view
where people_id is not NULL
) x
where row_num>1