简体   繁体   中英

ms sql server 2012 - deducing active rows for a time in the past using effective from and effective to dates

I have a table containing rows of pricing.

Each row has 3 timestamps, insert_date, effective_from and effective_to. (example row below)

I have a query that will show me instances where rows where the price has been wrongly entered as zero.

What I'd like to be able to do, is know what the price field was BEFORE the last update (I didn't want these to be updated to zero)

The query I have now is:

SELECT * 
FROM   company..database_pricing_fixed 
WHERE  price = 0 
       AND status = 1 
ORDER  BY insert_date DESC 

the table structure looks like this:

POSTCODE_KEY    EXP_ID  POSTCODE    SOURCE_POSTCODE_DISTRICT    DEST_POSTCODE_DISTRICT  PRICE   INSERT_DATE           EFFECTIVE_FROM    EFFECTIVE_TO    ACCOUNT_ID  STATUS    
W11_TW6 3XA       75    TW6 3XA          W11                          NULL                0       24/12/2013 01:32       24/12/2013 01:31   24/12/2013 03:41          32523 1

With SQL Server 2012, you can use LEAD() to get the second closest price if the latest one inserted is 0;

WITH cte AS (
  SELECT POSTCODE_KEY, EXP_ID, POSTCODE, SOURCE_POSTCODE_DISTRICT,
  DEST_POSTCODE_DISTRICT, 
    CASE WHEN PRICE = 0 
         THEN LEAD(PRICE) OVER (PARTITION BY POSTCODE_KEY 
                                ORDER BY INSERT_DATE DESC) 
         ELSE PRICE 
    END PRICE,   
    INSERT_DATE, EFFECTIVE_FROM, EFFECTIVE_TO, ACCOUNT_ID,STATUS, 
    ROW_NUMBER() OVER (PARTITION BY POSTCODE_KEY ORDER BY INSERT_DATE DESC) rn
  FROM DATABASE_pricing_fixed
)
SELECT * FROM cte WHERE rn=1

An SQLfiddle to test with .

I modified the DDL in Joachim's SQL Fiddle a bit and utilized this structure to find a SQL Server 2008 solution.

A_PRICE and B_PRICE are the original PRICE columns in each table of the LEFT JOIN. CALCULATED_PRICE is the price you want to use and is the result of determining if table A.PRICE is 0 and falling back to B.PRICE if it is. It furthermore falls back to 0 if a.PRICE is 0 and there is no preceding insert to reference. You can get rid of A_PRICE and B_PRICE.

SQL Fiddle

SEQ_A and SEQ_B are debugging values I used in my coding to help visualize the dataset. You can get rid of those.

Using this DDL:

CREATE TABLE DATABASE_pricing_fixed
    ([POSTCODE_KEY] varchar(11), [EXP_ID] int, [POSTCODE] varchar(7), [SOURCE_POSTCODE_DISTRICT] varchar(3), [DEST_POSTCODE_DISTRICT] varchar(4), [PRICE] int, [INSERT_DATE] varchar(16), [EFFECTIVE_FROM] varchar(16), [EFFECTIVE_TO] varchar(16), [ACCOUNT_ID] int, [STATUS] int)
;

INSERT INTO DATABASE_pricing_fixed
    ([POSTCODE_KEY], [EXP_ID], [POSTCODE], [SOURCE_POSTCODE_DISTRICT], [DEST_POSTCODE_DISTRICT], [PRICE], [INSERT_DATE], [EFFECTIVE_FROM], [EFFECTIVE_TO], [ACCOUNT_ID], [STATUS])
VALUES
    ('W11_TW6 3XA', 75, 'TW6 3XA', 'W11', NULL, 0, '24/12/2013 01:34', '24/12/2013 01:31', '24/12/2013 03:41', 32523, 1)
;
INSERT INTO DATABASE_pricing_fixed
    ([POSTCODE_KEY], [EXP_ID], [POSTCODE], [SOURCE_POSTCODE_DISTRICT], [DEST_POSTCODE_DISTRICT], [PRICE], [INSERT_DATE], [EFFECTIVE_FROM], [EFFECTIVE_TO], [ACCOUNT_ID], [STATUS])
VALUES
    ('W11_TW6 3XB', 75, 'TW6 3XA', 'W11', NULL, 47, '22/12/2013 01:32', '24/12/2013 01:31', '24/12/2013 03:41', 32523, 1)
;
INSERT INTO DATABASE_pricing_fixed
    ([POSTCODE_KEY], [EXP_ID], [POSTCODE], [SOURCE_POSTCODE_DISTRICT], [DEST_POSTCODE_DISTRICT], [PRICE], [INSERT_DATE], [EFFECTIVE_FROM], [EFFECTIVE_TO], [ACCOUNT_ID], [STATUS])
VALUES
    ('W11_TW6 3XC', 75, 'TW6 3XA', 'W11', NULL, 33, '24/12/2013 01:32', '24/12/2013 01:31', '24/12/2013 03:41', 32523, 1)
;

Solution:

WITH d1 AS (
  SELECT 
     *
    ,Seq = ROW_NUMBER() OVER (PARTITION BY POSTCODE ORDER BY INSERT_DATE)
  FROM DATABASE_pricing_fixed
)

SELECT a.POSTCODE_KEY
      ,a.EXP_ID
      ,a.POSTCODE
      ,a.SOURCE_POSTCODE_DISTRICT
      ,a.DEST_POSTCODE_DISTRICT
      ,A_PRICE = a.PRICE
      ,B_PRICE = b.PRICE
      ,CALCULATED_PRICE = COALESCE(NULLIF(a.PRICE, 0), b.PRICE, 0)
      ,a.INSERT_DATE
      ,a.EFFECTIVE_FROM
      ,a.EFFECTIVE_TO
      ,a.ACCOUNT_ID
      ,a.STATUS
      ,A_SEQ = a.Seq
      ,B_SEQ = b.Seq
FROM d1 a
LEFT JOIN d1 b
  ON  a.PRICE = 0 
  AND b.POSTCODE = a.POSTCODE
  AND a.Seq - b.Seq = 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM