2013-03-28 52 views
4

對不起混淆的標題。請告訴,如果可以通過數據庫請求來完成。假設我們有如下表選擇行數等於或低於給定值並且與其最接近的行

ind_id  name     value  date 
----------- -------------------- ----------- ---------- 
1   a     10   2010-01-01 
1   a     20   2010-01-02 
1   a     30   2010-01-03 
2   b     10   2010-01-01 
2   b     20   2010-01-02 
2   b     30   2010-01-03 
2   b     40   2010-01-04 
3   c     10   2010-01-01 
3   c     20   2010-01-02 
3   c     30   2010-01-03 
3   c     40   2010-01-04 
3   c     50   2010-01-05 
4   d     10   2010-01-05 

我需要查詢所有行,包括各ind_id一次給定的日期,如果有針對給定的日期沒有ind_id,然後採取就近下日期,如果沒有任何較低日期,然後用空值返回ind_id + name(名稱/ ind_id對相等)。 例如,日期是2010-01-04,我希望下面的結果:

ind_id  name     value  date 
----------- -------------------- ----------- ---------- 
1   a     30   2010-01-03 
2   b     40   2010-01-04 
3   c     40   2010-01-04 
4   d     NULL  NULL 

如果有可能,我會很感激,如果有人幫我查詢的建築。我使用SQL Server 2008的

+0

「名稱/ ind_id對相等」 - 這是否意味着對於給定的id,名稱將始終是相同的?如果是這樣,它表示數據庫模式中的非規範化,除非基礎數據來自多個表 - 顯示的數據是來自單個表還是來自多個表? –

+0

@Mark Ba​​nnister是的,我知道,這個表是另一個請求的結果:) –

+0

好吧,所以它是從一個表 - 謝謝。 –

回答

4

入住這SQL FIDDLE DEMO


with CTE_test 
as 
(
    select int_id, 
     max(date) MaxDate 
    from test 
    where date<='2010-01-04 00:00:00:000' 
    group by int_id 
) 
select A.int_id, A.[Value], A.[Date] 
from test A 
    inner join CTE_test B 
     on a.int_id=b.int_id 
      and a.date = b.Maxdate 
union all 
select int_id, null, null 
from test 
where int_id not in (select int_id from CTE_test) 
+0

欣賞深刻的洞察力,是的,以前的答案是錯誤的。 Timofei沒有要求最大值(價值)。我解答了答案和相應的演示。 – ljh

+0

好多了! +1 – dasblinkenlight

1

您可以使用類似:

declare @date date = '2010-01-04' 

;with ids as 
(
    select distinct ind_id 
    from myTable 
) 
,ranks as 
(
    select * 
    , ranking = row_number() over (partition by ind_id order by date desc) 
    from myTable 
    where date <= @date 
) 
select ids.ind_id 
    , ranks.value 
    , ranks.date 
from ids 
    left join ranks on ids.ind_id = ranks.ind_id and ranks.ranking = 1 

SQL Fiddle with demo

理想情況下,您不會使用DISTINCT語句來獲取ind_id值,但在此情況下,我已經使用它來獲得所需的結果。

此外,這些查詢的標準免責聲明;如果您有重複的數據,則應考慮ORDER BY中的決勝列或使用RANK而不是ROW_NUMBER

有機磷農藥後編輯更新

只需添加新的列到現有的查詢:

with ids as 
(
    select distinct ind_id, name 
    from myTable 
) 
,ranks as 
(
    select * 
    , ranking = row_number() over (partition by ind_id order by date desc) 
    from myTable 
    where date <= @date 
) 
select ids.ind_id 
    , ids.name 
    , ranks.value 
    , ranks.date 
from ids 
    left join ranks on ids.ind_id = ranks.ind_id and ranks.ranking = 1 

SQL Fiddle with demo

與上一個一樣,如果可用,最好通過加入一個常規數據表來獲得ind_id/name信息。

0

這不是確切的答案,但會給你的概念,因爲我只是寫下來,沒有任何測試。

use 
go 
if 
(Select value from table where [email protected]) is not null 
--you code to get the match value 
else if 
(Select LOWER(Date) from table) is not null 
-- your query to get the nerst dtae record 
else 
--you query withh null value 
end 
2

(更新)嘗試:

with cte as 
(select m.*, 
     max(date) over (partition by ind_id) max_date, 
     max(case when date <= @date then date end) over 
      (partition by ind_id) max_acc_date 
from myTable m) 
select ind_id, 
     name, 
     case when max_acc_date is null then null else value end value, 
     max_acc_date date 
from cte c 
where date = coalesce(max_acc_date, max_date) 

(SQLFiddle here

1

這裏是返回,你正在尋找的結果的查詢:

SELECT 
    t1.ind_id 
, CASE WHEN t1.date <= '2010-01-04' THEN t1.value ELSE null END 
FROM test t1 
WHERE t1.date=COALESCE(
    (SELECT MAX(DATE) 
    FROM test t2 
    WHERE t2.ind_id=t1.ind_id AND t2.date <= '2010-01-04') 
, t1.date) 

的想法是在相關查詢中選擇一行,使其ID與當前行的ID匹配,並且日期是在您的目標日期爲'2010-01-04'之前最高。

當這樣的行不存在時,返回當前行的日期。這個日期需要被替換爲null;這是頂部的CASE聲明正在做的事情。

這裏是demo on sqlfiddle

1

EXISTS運算符使用選項

DECLARE @date date = '20100104' 
SELECT ind_id, 
     CASE WHEN date <= @date THEN value END AS value, 
     CASE WHEN date <= @date THEN date END AS date 
FROM dbo.test57 t 
WHERE EXISTS (
       SELECT 1 
       FROM dbo.test57 t2 
       WHERE t.ind_id = t2.ind_id AND t2.date <= @date 
       HAVING ISNULL(MAX(t2.date), t.date) = t.date 
      ) 

演示上SQLFiddle

1

嘗試

DECLARE @date DATETIME; 

SET @date = '2010-01-04'; 

WITH temp1 AS 
(
SELECT t.ind_id 
, t.name 
, CASE WHEN t.date <= @date THEN t.value ELSE NULL END AS value 
, CASE WHEN t.date <= @date THEN t.date ELSE NULL END AS date 
FROM test1 AS t 
), 

temp AS 
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ind_id ORDER BY t.date DESC) AS rn 
FROM temp1 AS t 
WHERE t.date <= @date OR t.date IS NULL 
) 

SELECT * 
FROM temp AS t 
WHERE rn = 1 
相關問題