相关文章推荐
多情的大象  ·  SQL UNION 合并两个或多个 ...·  4 小时前    · 
文雅的海龟  ·  IBM Documentation·  4 小时前    · 
耍酷的红烧肉  ·  5分钟搞懂MySQL - ...·  2 小时前    · 

如何在SQL Server中根据一个条件选择两列数据?

0 人关注

我有一个表 ,请看Fiddle 。它包含了用户在3次不同访问中的尺寸细节。我的问题是,我怎样才能从每个用户的三个尺寸列中选择最小尺寸,并从最小尺寸的三个日期列中选择各自的日期?我想我可以从下面的查询中得到最小尺寸,但各自的日期,不确定?

Select 
    Name,
        When Size1 < Size2 And Size1 < Size3 Then Size1
        When Size2 < Size1 And Size2 < Size3 Then Size2 
        Else Size3
    End As MinSize

这就是我在寻找的东西

╔══════╦════════════╦═════════╗
║ name ║   visit    ║ minSize ║
╠══════╬════════════╬═════════╣
║ ABC  ║ 2014-02-01100 ║
║ DEF  ║ 2014-01-01100 ║
║ GHI  ║ 2014-02-0150 ║
║ JKL  ║ 2014-03-01300 ║
╚══════╩════════════╩═════════╝
    
6 个评论
你是否有可能将数据库规范化?例如,将用户名、访问量、大小作为列。
我认为不是,每次访问的数据是单独记录的。
与自己交叉连接如何?
jpw
如果两次或多次访问的尺寸相同怎么办?那你会选择哪个日期?
@Nimko "每次访问的数据都是单独记录的" ,这与你链接的SQL Fiddle有直接矛盾。
@Andrew,对不起,我的意思是存储在同一个表中。第一张。我想我还需要使用isNull函数来处理null,因为大小值不能与null比较。
sql
sql-server
sql-server-2008
Nimko
Nimko
发布于 2015-09-14
4 个回答
GarethD
GarethD
发布于 2015-09-14
0 人赞同

你可以 用表值构造器 把你的3次访问解成3行,然后按大小顺序选择最上面的1行。

SELECT  t.username,
        ms.Visit,
        MinSize = ms.Size
FROM    Test AS t
        CROSS APPLY
        (   SELECT  TOP 1 m.visit, m.size
            FROM    (VALUES 
                        (1, t.visit1, t.size1), 
                        (2, t.visit2, t.size2), 
                        (3, t.visit3, t.size3)
                    ) AS m (VisitNo, Visit, Size)
            ORDER BY m.Size 
        ) AS ms;

如果你有更多的列,只需在你的表值构造器中添加更多的行即可

SELECT  t.username,
        ms.Visit,
        MinSize = ms.Size
FROM    Test AS t
        CROSS APPLY
        (   SELECT  TOP 1 m.visit, m.size
            FROM    (VALUES 
                        (1, t.visit1, t.size1), 
                        (2, t.visit2, t.size2), 
                        (3, t.visit3, t.size3), 
                        (4, t.visit4, t.size4),  -- New values added for more columns
                        (5, t.visit5, t.size5), 
                        (6, t.visit6, t.size6), 
                        (7, t.visit7, t.size7)
                    ) AS m (VisitNo, Visit, Size)
            ORDER BY m.Size 
        ) AS ms;
    
这只是一个样本表,你的查询对一个长表来说能成立吗?
我认为没有理由不这样做。但发现问题的最好办法是尝试一下。
对不起,我是新手。我不明白第二部分的意思。你能不能更新一下查询,当有一个测试表的时候,其中有用户名、大小1、大小2、大小3、大小4、大小5、大小6、大小7、访问1、访问2、访问3、访问4、访问5、访问6、访问7等列。我想我不需要数值等,是吗?
StackUser
StackUser
发布于 2015-09-14
已采纳
0 人赞同

像这样试试。

CREATE TABLE test
     username VARCHAR(50),
     visit1   DATETIME,
     visit2   DATETIME,
     visit3   DATETIME,
     size1    INT,
     size2    INT,
     size3    INT
INSERT INTO test
VALUES     ( 'ABC',
             '2014-01-01',
             '2014-02-01',
             '2014-03-01',
             200,
             100,
             300 );
INSERT INTO test
VALUES     ( 'EFG',
             '2014-01-01',
             '2014-02-01',
             '2014-03-01',
             100,
             200,
             300 );
INSERT INTO test
VALUES     ( 'HIJ',
             '2014-01-01',
             '2014-02-01',
             '2014-03-01',
             400,
             100 );
INSERT INTO test
VALUES     ( 'KLM',
             '2014-01-01',
             '2014-02-01',
             '2014-03-01',
             600,
             100,
             300 );
SELECT UserName,
             WHEN Size1 < Size2
                  AND Size1 < Size3 THEN Visit1
             WHEN Size2 < Size1
                  AND Size2 < Size3 THEN Visit2
             ELSE visit3
           END AS Date,
             WHEN Size1 < Size2
                  AND Size1 < Size3 THEN Size1
             WHEN Size2 < Size1
                  AND Size2 < Size3 THEN Size2
             ELSE Size3
           END AS MinSize
    FROM   Test 
    
我刚刚发现,有一些空值,而大小值没有与空值进行比较。有什么建议吗?
jpw
如果尺寸1和尺寸2相同,即使尺寸3更高,也会被选中。
jpw
jpw
发布于 2015-09-14
0 人赞同

这可能比它需要的要复杂一些,但有一个选择是使用联合起来的查询来规范数据,然后使用row_number、rank或dense_rank来给行编号。

select * 
from (
    select *, r = row_number() over (partition by username order by size) 
    from (
       select username, visit1 as visit, size1 as size from test
       union all
       select username, visit2 as visit, size2 as size from test
       union all
       select username, visit3 as visit, size3 as size from test
where r = 1;

如果大小值为空,你应该在最里面的查询中使用isnull或coalesce。

KumarHarsh
KumarHarsh
发布于 2015-09-14
0 人赞同

试试这个。

declare  @test table
  username varchar(50),
  visit1 datetime,
  visit2 datetime,
  visit3 datetime,
  size1 int,
  size2 int,
  size3 int
  insert into @test Values( 'ABC', '2014-01-01', '2014-02-01', '2014-03-01', 200, 100, 300 );
  insert into @test Values( 'EFG', '2014-01-01', '2014-02-01', '2014-03-01', 100, 200, 300 );
  insert into @test Values( 'HIJ', '2014-01-01', '2014-02-01', '2014-03-01', 400, 50, 100 );
  insert into @test Values( 'KLM', '2014-01-01', '2014-02-01', '2014-03-01', 600, 100, 300 );
--select * from @test