2013-03-28 17 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 
相关问题