2

I want to select data based on a date range in a table and also get the latest value before that date range.

How can I make this more efficient?

The table is defined as:

Name       varchar(100)   Checked
DataType   varchar(100)   Checked
Time       datetime       Checked
Value      int            Checked

The table contains the following data:

Name    DataType  Time                      Value
Name1   Type1     2010-09-29 17:29:00.000   999
Name2   Type2     2013-11-02 06:51:00.000   0

I have created the following query which is a little long winded but it does return the correct results. However, I want to know if this can be achieved using better T-SQL?

I am going to write the code as in-line SQL within my application

DECLARE @effectiveFrom DATETIME
SET @effectiveFrom = '2010-09-29 17:30:00'
DECLARE @effectiveTo DATETIME
SET @effectiveTo = '2010-09-29 17:49:00'
DECLARE @bmunit varchar(100)
DECLARE @datatype varchar(100)

--Select * from [Table] 
--where  (Time >= '2010-09-29 17:30:00' and Time < '2010-09-29     17:49:00') 

--union Select top 1 * from [Table]
-- where  Time < '2010-09-29 17:30:00' order by Time desc
SELECT P1.[Name]
      ,P1.[DataType]
      ,P1.[Time]
      ,P1.[Value]
      ,P1.Que
FROM
(
  SELECT  [Name]
      ,[DataType]
      ,[Time]
      ,[Value]
      , 'between' AS [Que]
  FROM [Table]
  WHERE  Time >= @effectiveFrom AND  EffectiveTime < @effectiveTo
) P1   
UNION SELECT P2.[Name]
      ,P2.[DataType]
      ,P2.[Time]
      ,P2.[Value]
      , 'before' AS [Que]
FROM
(
  SELECT TOP 1 [Name]
      ,[DataType]
      ,Time]
      ,[Value]
  FROM [Table] P1
  WHERE  Time < @effectiveFrom

) P2 --ON P1.[Name] = P2.[Name] AND P1.[DataType] = P2.[DataType]
WHERE Name = 'MyName' --AND P1.Time >= @effectiveFrom AND P1.Time < @effectiveTo
ORDER BY 2,3  
1
  • Which exactly is your RDBMS? MySQL or SQL Server? Commented Nov 11, 2013 at 12:28

1 Answer 1

2

You should be able to pare it down to something like this:

SELECT P1.[Name]
      ,P1.[DataType]
      ,P1.[Time]
      ,P1.[Value]
      ,'between' AS Que
FROM [Table] P1
WHERE Time >= @effectiveFrom AND Time < @effectiveTo
      AND Name = 'MyName'
UNION ALL
SELECT * FROM (
    SELECT TOP 1 P2.[Name]
          ,P2.[DataType]
          ,P2.[Time]
          ,P2.[Value]
          ,'before' AS [Que]
    FROM [Table] P2
    WHERE Time < @effectiveFrom
          AND Name = 'MyName'
    ORDER BY 3
) A

If you don't like repeating the name check, the select will get a bit bigger:

SELECT * FROM (
    SELECT P1.[Name]
          ,P1.[DataType]
          ,P1.[Time]
          ,P1.[Value]
          ,'between' AS Que
    FROM [Table] P1
    WHERE Time >= @effectiveFrom AND Time < @effectiveTo
    UNION ALL
    SELECT * FROM (
        SELECT TOP 1 P2.[Name]
            ,P2.[DataType]
            ,P2.[Time]
            ,P2.[Value]
            ,'before' AS [Que]
        FROM [Table] P2
        WHERE Time < @effectiveFrom
        ORDER BY 3
    ) A
) B
WHERE Name = 'MyName'

If you want to make it shorter, you can try this but I think it's less readable:

SELECT P1.[Name]
      ,P1.[DataType]
      ,P1.[Time]
      ,P1.[Value]
      ,(CASE WHEN Time >= @effectiveFrom THEN 'between' ELSE 'before' END) AS Que
FROM [Table] P1
WHERE Name = 'MyName'
      AND 
      (
          (Time >= @effectiveFrom AND Time < @effectiveTo)
          OR (Time < @effectiveFrom AND NOT EXISTS (SELECT * 
                                                FROM [Table] P2 
                                                WHERE Time < @effectiveFrom
                                                    AND P2.Time > P1.Time)
          )
      )

Is it even shorter?

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.