Domanda

I'm a bit of a SQL newb but have been tasked with coming up with some code to retrieve values from a historian database. I'm retrieving the name of an object (tag) and its value at a specific time every month of the year. However, the year will be user defined parameter coming from a report. So if the user selects 2014 it should query on 1/1/2014,2/1/2014 and so on.

I came up with the simple part of the query which is looking up the tag names and associated values:

SELECT Tagname,value  
   From runtime.dbo.History
   WHERE Tagname IN ('Tag1', 'Tag2')
   and wwVersion = 'Latest'
   and DateTime = @Date

Here are the issues I need to solve: 1. I can manually set the @Date but I'd like to have it do whats described above. I'm thinking some type of loop might be used? 2. I'm not sure how to output it into table format to look like:

Tag 1, (jan value), (feb value), (mar value), etc...
Tag 2, (jan value), (feb value), (mar value), etc...

Any help would be appreciated. Thanks!

È stato utile?

Soluzione

If you will only have one value per tag per month, you can use a conditional aggregate to choose your record. I have gone for the MAX function, but if you only have one value it is arbitrary:

DECLARE @Year INT;
SET @Year = 2013;

-- CONVERT TO A DATE TO ALLOW A SARGEABLE PREDICATE IN THE WHERE CLAUSE
DECLARE @Date SMALLDATETIME;
SET @Date = CONVERT(SMALLDATETIME, CONVERT(CHAR(4), @Year) + '0101', 112);

SELECT  Tagname,
        Jan = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 1 THEN value END),
        Feb = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 2 THEN value END),
        Mar = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 3 THEN value END),
        Apr = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 4 THEN value END),
        May = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 5 THEN value END),
        Jun = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 6 THEN value END),
        Jul = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 7 THEN value END),
        Aug = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 8 THEN value END),
        Sep = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 9 THEN value END),
        Oct = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 10 THEN value END),
        Nov = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 11 THEN value END),
        Dec = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 12 THEN value END)
FROM    runtime.dbo.History
WHERE   Tagname IN ('Tag1', 'Tag2')
AND     wwVersion = 'Latest'
AND     DateTime >= @Date
AND     DateTime < DATEADD(YEAR, 1, @Date)
GROUP BY TagName;

If you will have multiple values then you will need to apply some sort of logic to chose the correct one. In the below example I have gone for the first value for each month:

DECLARE @Year INT;
SET @Year = 2013;

-- CONVERT TO A DATE TO ALLOW A SARGEABLE PREDICATE IN THE WHERE CLAUSE
DECLARE @Date SMALLDATETIME;
SET @Date = CONVERT(SMALLDATETIME, CONVERT(CHAR(4), @Year) + '0101', 112);

SELECT  Tagname,
        Jan = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 1 THEN value END),
        Feb = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 2 THEN value END),
        Mar = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 3 THEN value END),
        Apr = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 4 THEN value END),
        May = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 5 THEN value END),
        Jun = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 6 THEN value END),
        Jul = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 7 THEN value END),
        Aug = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 8 THEN value END),
        Sep = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 9 THEN value END),
        Oct = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 10 THEN value END),
        Nov = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 11 THEN value END),
        Dec = MAX(CASE WHEN DATEPART(MONTH, DateTime) = 12 THEN value END)
FROM    (   SELECT  TagName, 
                    DateTime,
                    Value,
                    RowNum = ROW_NUMBER() OVER(PARTITION BY TagName, DATEPART(MONTH, DateTime), DATEPART(YEAR, DateTime)
                                                ORDER BY DateTime)
            FROM    runtime.dbo.History
            WHERE   Tagname IN ('Tag1', 'Tag2')
            AND     wwVersion = 'Latest'
            AND     DateTime >= @Date
            AND     DateTime < DATEADD(YEAR, 1, @Date)
        ) h
WHERE   h.RowNum = 1
GROUP BY TagName;

Altri suggerimenti

  1. You want to query data in a period, so DateTime should be in a range. eg. DateTime > @DateStart and DateTime < @DateEnd.
  2. If you want to query data with Tag1 first and then data with Tag2, try group by clause. If you need to add some table header, you may query data in a loop, query data with the same tag at each time.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top