I have 2 tables and am joining them on tinnumber, but we group the records based on PSKUCD so that we have a family of tinumbers under each pskucd. We are joining with MDM table because it has updated brandname. And MDM will have only parent tinumbers. I want to use the mdm brandname from table 2 to update for parent and child tinumber's brandname in snapshot table.
Table 1 (snapshot)
Pskucd tinnum brandname
234 9999 AMZ
234 10001 AMZt
Table 2 (MDM)
tinnum bdname
9999 RMZ
Desired Output
Pskucd tinnum brandname bdname
234 9999 AMZ RMZ
234 10001 AMZt RMZ
One option might be to use outer join with first_value analytic function (sample data from line #1 - 7; query that does the job begins at line #9).
SQL> with
2 snapshot (pskucd, tinnum, brandname) as
3 (select 234, 9999 , 'AMZ' from dual union all
4 select 234, 10001, 'AMZt' from dual
5 ),
6 mdm (tinnum, bdname) as
7 (select 9999, 'RMZ' from dual)
8 --
9 select s.pskucd,
10 s.tinnum,
11 s.brandname,
12 first_value(m.bdname) over (order by null) bdname
13 from snapshot s left join mdm m on m.tinnum = s.tinnum;
PSKUCD TINNUM BRANDNAME BDNAME
---------- ---------- ---------- ----------
234 9999 AMZ RMZ
234 10001 AMZt RMZ
SQL>
I need help with a transitive query in SQL Server.
I have a table with [ID] and [GRPID].
I would like to update a third column [NEWGRPID] based on the following logic:
For each [ID], get its GRPID;
Get all of the IDs associated with the GRPID from (1);
Set [NEWGRPID] equal to an integer (variable that is incremented by 1), for all of the rows from step (2)
The idea is several of these IDs are "transitively" linked across different [GRPID]s, and should all be having the same [GRPID].
The below table is the expected result, with [NEWGRPID] populated.
ID GRPID NEWGRPID
----- ----- ------
1 345 1
1 777 1
2 777 1
3 345 1
3 777 1
4 345 1
4 999 1
5 345 1
5 877 1
6 999 1
7 877 1
8 555 2
9 555 2
Try this code:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL
BEGIN
DROP TABLE #tmp;
END;
SELECT GRPID, count (*) AS GRPCNT
INTO #tmp
FROM yourtable
GROUP BY GRPID
UPDATE TGT
SET TGT.NEWGRPID = SRC.GRPCNT
FROM yourtable TGT
JOIN #tmp ON #tmp.GRPID = TGT.GRPID
If the values are likely to change over time you should think about a computed column or a trigger.
I have data where people have changed role mid month and want to count the activity after their new start date. Can I use the results of a table as a dynamic Query, I have a query which returns the following resultset:-
Firstname Surname StartDate
----------------------------------
Jon Smith 2015-01-01
Paul Jones 2014-07-23
...
So the query would look something like:
SELECT Firstname +' '+ surname, month, count(1) FROM dataTable
WHERE (Firstname='John' AND Surname='Smith' AND date >=2015-01-01)
OR (Firstname='Paul' AND Surname='Jones' AND date >=2014-07-23)
OR ...
but the number of 'ORs' would depend on the number of rows in the first table
Name Month Count
----------------------------------
Jon Smith 1 15
Paul Jones 1 16
Jon Smith 2 30
Paul Jones 2 25
Charlie Gu 1 52
Which I can then pivot to get
Name 1 2
--------------------------
Jon Smith 15 30
Paul Jones 16 25
Charlie Gu 52 NULL
Thanks in advance
It seems to me that Ako is right and a simple join should do the trick rather than a dynamic query.
declare #NewStartDates table
(
Firstname nvarchar(100),
Surname nvarchar(100),
StartDate date
);
insert into #NewStartDates
(Firstname, Surname, StartDate)
values (N'Jon', N'Smith', '20150101'),
(N'Paul', N'Jones', '20140723');
select d.Firstname,
d.Surname,
year(d.Date) * 100 + month(d.Date) as Period,
count(*) as ActivityCount
from dataTable as d
inner join #NewStartDates as n
on d.Firstname = n.Firstname
and d.Surname = n.Surname
and d.Date >= n.StartDate
group by d.Firstname,
d.Surname,
year(d.Date) * 100 + month(d.Date);
Please refer this - it will give you complete idea how you can get dynamic column query.Dynamic Column Generation - Pivot [SQL]
Doing some stats page for my skydiving club I have two SQL queries I would like to merge.
One shows the top three jumpers with the most jumps on the first load this year:
select top 3 ROW_NUMBER() OVER(ORDER BY count(1) desc) AS Nr
, vc.sCust as Name
, count(1) as JumpsCount
from dbo.ViewInvoice vi with(nolock)
join dbo.viewCust vc
on vi.wCustId = vc.wCustId
where year(vi.dtProcess) = year(getdate())
and vi.nMani = 1
group by vc.sCust
order by count(1) desc
OUTPUT:
-- Nr Name JumpsCount
-- 1 Tom Awesome 17
-- 2 Alan Jackson 16
-- 3 John Thebest 13
The next query shows all the years of jumping in the DB:
select distinct year(vi.dtProcess) As Datum
from dbo.ViewInvoice vi
order by 1
OUTPUT:
-- Datum
-- 2010
-- ...
-- 2014
What I would like is to get a query that merge the results with an output like this:
-- Datum Nr Name Jumpscount
-- 2010 1 Some OldVeteran 100
-- 2010 2 Alan Jackson 96
-- 2010 3 Gordon McGann 89
-- ...
-- 2014 1 Tom Awesome 17
-- 2014 2 Alan Jackson 16
-- 2014 3 John Thebest 13
Changed to RANK so jumpers with same amount of jumps gets the same postion.
WITH JumpsPerYear AS (
SELECT YEAR(dtProcess) AS [Year]
,wCustId
,COUNT(1) AS JumpsCount
FROM ViewInvoice
WHERE nMani = 1 -- first load/manifest number
GROUP BY YEAR(dtProcess)
,wCustId
)
,RankPerYear AS (
SELECT [Year]
,wCustId
,RANK() OVER (PARTITION BY [Year] ORDER BY JumpsCount DESC) AS [Rank]
,JumpsCount
FROM JumpsPerYear
)
SELECT RankPerYear.[Year] AS Datum
,RankPerYear.[Rank] AS Nr
,ViewCust.sCust AS Name
,RankPerYear.JumpsCount
FROM RankPerYear
INNER JOIN ViewCust
ON ViewCust.wCustId = RankPerYear.wCustId
WHERE RankPerYear.[Rank] <= 3
ORDER BY RankPerYear.[Year]
,RankPerYear.[Rank]
Hi I have a table of meter values in a SQL Server database, which contains a table with the following columns:
Timestamp, meterID, rawValue
I am trying to graph the water usage rate using a query and google charts, the problem is that I need to calculate the rate from the raw meter values which are updated every 15 to 30 minutes.
I want to run a query that returns the values for a specific water meter.
MeterID, Timestamp, (rawValue-previousRawValue)/(timestamp difference in seconds)
any help is much appreciated.
Edit 1: I have modified index definition to eliminate LookUp operator => fewer logical reads.
Edit 2: I have added the second solution based on quirky update method. Please read this article (Solving the Running Total and Ordinal Rank Problems) written by Jeff Moden.
First solution can be tested with SQL Server 2005/2008:
--Create test table
CREATE TABLE dbo.MeterValues
(
ID INT IDENTITY(1,1) PRIMARY KEY
,[Timestamp] DATETIME NOT NULL
,MeterID INT NOT NULL
,RawValue INT NOT NULL
);
CREATE UNIQUE INDEX IUN_MeterValues_MeterID_Timestamp
--SQL Server 2008
ON dbo.MeterValues (MeterID, [Timestamp])
INCLUDE (RawValue)
--SQL Server 2005
--ON dbo.MeterValues (MeterID, [Timestamp],RawValue)
--DROP INDEX dbo.MeterValues.IUN_MeterValues_MeterID_Timestamp
--Insert some values
INSERT dbo.MeterValues ([Timestamp], MeterID, RawValue)
SELECT '2011-01-01T00:00:00', 1, 100
UNION ALL
SELECT '2011-01-01T00:00:15', 1, 105
UNION ALL
SELECT '2011-01-01T00:00:30', 1, 102
UNION ALL
SELECT '2011-01-01T00:00:45', 1, 108
UNION ALL
SELECT '2011-01-01T00:01:00', 1, 109
UNION ALL
SELECT '2011-01-01T00:00:00', 2, 1000
UNION ALL
SELECT '2011-01-01T00:00:15', 2, 900
UNION ALL
SELECT '2011-01-01T00:00:30', 2, 1105
UNION ALL
SELECT '2011-01-01T00:00:45', 2, 1050
UNION ALL
SELECT '2011-01-01T00:01:00', 2, 910;
--Check test data
SELECT *
FROM dbo.MeterValues mv
ORDER BY mv.MeterID, mv.ID DESC;
--Solution
WITH ValuesWithRowNumber
AS
(
SELECT mv.MeterID
,mv.RawValue
,mv.[Timestamp]
,ROW_NUMBER() OVER(PARTITION BY mv.MeterID ORDER BY mv.[Timestamp] ASC) RowNum
FROM dbo.MeterValues mv
)
SELECT crt.MeterID
,crt.[Timestamp] AS CrtTimestamp
,prev.[Timestamp] AS PrevTimestamp
,crt.RawValue AS CrtRawValue
,prev.RawValue AS PrevRawValue
,(crt.RawValue - prev.RawValue)*1.00/DATEDIFF(SECOND, prev.[Timestamp], crt.[Timestamp]) Diff
,STR((crt.RawValue - prev.RawValue)*1.00/DATEDIFF(SECOND, prev.[Timestamp], crt.[Timestamp])*100, 10, 2)+'%' [Percent]
FROM ValuesWithRowNumber crt --crt=current
LEFT JOIN ValuesWithRowNumber prev ON crt.MeterID = prev.MeterID --prev=previous
AND crt.RowNum - 1 = prev.RowNum
ORDER BY crt.MeterID, crt.[Timestamp] DESC;
--By, by
DROP TABLE dbo.MeterValues;
Results:
MeterID CrtTimestamp PrevTimestamp CrtRawValue PrevRawValue Diff Percent
----------- ----------------------- ----------------------- ----------- ------------ --------------------------------------- -----------
1 2011-01-01 00:01:00.000 2011-01-01 00:00:45.000 109 108 0.0666666666666 6.67%
1 2011-01-01 00:00:45.000 2011-01-01 00:00:30.000 108 102 0.4000000000000 40.00%
1 2011-01-01 00:00:30.000 2011-01-01 00:00:15.000 102 105 -0.2000000000000 -20.00%
1 2011-01-01 00:00:15.000 2011-01-01 00:00:00.000 105 100 0.3333333333333 33.33%
1 2011-01-01 00:00:00.000 NULL 100 NULL NULL NULL
2 2011-01-01 00:01:00.000 2011-01-01 00:00:45.000 910 1050 -9.3333333333333 -933.33%
2 2011-01-01 00:00:45.000 2011-01-01 00:00:30.000 1050 1105 -3.6666666666666 -366.67%
2 2011-01-01 00:00:30.000 2011-01-01 00:00:15.000 1105 900 13.6666666666666 1366.67%
2 2011-01-01 00:00:15.000 2011-01-01 00:00:00.000 900 1000 -6.6666666666666 -666.67%
2 2011-01-01 00:00:00.000 NULL 1000 NULL NULL NULL
The second solution can/should work with SQL 2000/2005/2008 (please read "The RULES" section from Jeff Moden article):
--Create test table
CREATE TABLE dbo.MeterValues
(
MeterID INT NOT NULL
,[Timestamp] DATETIME NOT NULL
,RawValue INT NOT NULL
,Diff NUMERIC(10,3) NULL
,PRIMARY KEY CLUSTERED(MeterID,[Timestamp])
);
--Insert some values
INSERT dbo.MeterValues ([Timestamp], MeterID, RawValue)
SELECT '2011-01-01T00:00:00', 1, 100
UNION ALL
SELECT '2011-01-01T00:00:15', 1, 105
UNION ALL
SELECT '2011-01-01T00:00:30', 1, 102
UNION ALL
SELECT '2011-01-01T00:00:45', 1, 108
UNION ALL
SELECT '2011-01-01T00:01:00', 1, 109
UNION ALL
SELECT '2011-01-01T00:00:00', 2, 1000
UNION ALL
SELECT '2011-01-01T00:00:15', 2, 900
UNION ALL
SELECT '2011-01-01T00:00:30', 2, 1105
UNION ALL
SELECT '2011-01-01T00:00:45', 2, 1050
UNION ALL
SELECT '2011-01-01T00:01:00', 2, 910;
--Check test data
SELECT *
FROM dbo.MeterValues mv
ORDER BY mv.MeterID, mv.[Timestamp];
DECLARE #OldRawValue INT
,#Diff NUMERIC(10,3)
,#OldMeterID INT
,#OldTimestamp DATETIME;
PRINT '*****Star*****'
--Calculations
UPDATE dbo.MeterValues WITH(TABLOCKX)
SET #Diff = CASE WHEN #OldMeterID = MeterID THEN (RawValue - #OldRawValue)*1.00/DATEDIFF(SECOND,#OldTimeStamp,[TimeStamp]) END
,Diff = #Diff
,#OldRawValue = RawValue
,#OldMeterID = MeterID
,#OldTimestamp = [Timestamp]
OPTION(MAXDOP 1);
--Results
SELECT *
FROM dbo.MeterValues mv
ORDER BY mv.MeterID, mv.[Timestamp];
PRINT '*****Stop*****'
--By, by
DROP TABLE dbo.MeterValues;
Results:
MeterID Timestamp RawValue Diff
----------- ----------------------- ----------- ---------------------------------------
1 2011-01-01 00:01:00.000 109 0.067
1 2011-01-01 00:00:45.000 108 0.400
1 2011-01-01 00:00:30.000 102 -0.200
1 2011-01-01 00:00:15.000 105 0.333
1 2011-01-01 00:00:00.000 100 NULL
2 2011-01-01 00:01:00.000 910 -9.333
2 2011-01-01 00:00:45.000 1050 -3.667
2 2011-01-01 00:00:30.000 1105 13.667
2 2011-01-01 00:00:15.000 900 -6.667
2 2011-01-01 00:00:00.000 1000 NULL
Try this
Select a.metered,a.timestamp,
(a.rawValue-b.rawValue)/(a.timestamp-b.timestamp)
From meters A
Join (selec top 2 rawValue,Timestamp
From meters where metered = #meter
order by timestamp DESC) b
On b.timestamp <> a.timestamp and a.meterId=B.meterId
Added a DESC to the timestamp in the middle query. This will cause the most recent two timestamps to be returned, and then the JOIN will "filter out" the one that matches the current row from A
I made a few minor changes to both my query and #Bogdan's query to make them as similar as possible, then compared them. Bogdan's modified query is at the bottom of this post.
Stacked together in the same query, according to the SQL Server Query Execution Plan, mine is 53% of the query cost, and Bogdan's is 47%.
For the data set offered in the Bogdan's post:
My query: 6 scans and 27 logical reads
Bogdan's: 6 scans and 72 logical reads
I added values every 15secs up to 5mins for both meterID 1 and 2, for a total of 42 records, then reran the queries with SQL Server Profiler.
Where my query wins on reads, Bogdan's still wins on CPU and Duration.
CPU SCANS READS DURATION
--------------------------------------
Mine 47 22 313 249ms
Bogdan's 16 22 972 15ms
--------------------------------------
I'm making a few assumptions, like that your MeterID is an INT. Change that as necessary.
I'm also assuming since you want to run the query for a specific meter ID, that it will be passed in as a parameter to a stored procedure.
This should work on SQL Server 2005 and later.
I do a few things that might distract from the actual solution. The core logic is really within the WHILE loop.
CREATE PROCEDURE [dbo].[GetMeterResults]
#MeterID INT
AS
BEGIN
-- create a temp table to store results
CREATE TABLE #tempResults
(
MeterID INT,
[Timestamp] DATETIME,
Result FLOAT
)
DECLARE
#Timestamp DATETIME,
#RawValue INT,
#LastTimestamp DATETIME,
#LastRawValue INT,
#FirstRun BIT = 1
DECLARE cr CURSOR FAST_FORWARD FOR
SELECT
[Timestamp],
RawValue
FROM
YourTable
WHERE
MeterID = #MeterID
ORDER BY
[Timestamp]
OPEN cr
FETCH NEXT FROM cr INTO #Timestamp, #RawValue
WHILE (##FETCH_STATUS = 0)
BEGIN
IF (#FirstRun = 1)
BEGIN -- the first run
SELECT #FirstRun = 0 -- flip the bit for all future runs
END
ELSE -- all subsequent runs after the first
BEGIN
INSERT INTO
#tempResults
SELECT
#MeterID,
#Timestamp,
(#RawValue - #LastRawValue) * 1.00 / DATEDIFF(s, #LastTimestamp, #Timestamp)
END
-- save the current values for comparison on the next run
SELECT
#LastTimestamp = #Timestamp,
#LastRawValue = #RawValue
FETCH NEXT FROM cr INTO #Timestamp, #RawValue
END
CLOSE CR
DEALLOCATE CR
-- return the result set
SELECT
*
FROM
#tempResults
-- clean up the temp table
DROP TABLE #tempResults
END
GO
Bogdan's modified query that filters by MeterID for an apples-to-apples comparison with my query above:
DECLARE #MeterID INT = 1;
WITH ValuesWithRowNumber
AS
(
SELECT mv.MeterID
,mv.RawValue
,mv.[Timestamp]
,ROW_NUMBER() OVER(PARTITION BY mv.MeterID ORDER BY mv.[Timestamp] ASC) RowNum
FROM dbo.MeterValues mv
WHERE mv.MeterID = #MeterID
)
SELECT crt.MeterID
,crt.[Timestamp] AS CrtTimestamp
,prev.[Timestamp] AS PrevTimestamp
,crt.RawValue AS CrtRawValue
,prev.RawValue AS PrevRawValue
,(crt.RawValue - prev.RawValue)*1.00/DATEDIFF(SECOND, prev.[Timestamp], crt.[Timestamp]) Diff
FROM ValuesWithRowNumber crt --crt=current
JOIN ValuesWithRowNumber prev ON crt.RowNum - 1 = prev.RowNum
ORDER BY crt.[Timestamp];