我在蜂巢里有张桌子,看起来像:
| Name | 1990 | 1991 | 1992 | 1993 | 1994 |
| Rex | 0 | 0 | 1 | 1 | 1 |
| Max | 0 | 0 | 0 | 0 | 1 |
| Phil | 1 | 1 | 1 | 1 | 1 |
对于每一行,我都想得到第一列的名称,它是非零的,所以类似于:
| Name | Column |
| Rex | 1992 |
| Max | 1994 |
| Phil | 1990 |
对于每一行,保证:
发布于 2021-11-28 17:04:24
有一个“琐碎”的解决方案(下面),它假设问题中的保证是有效的--他们今天很可能会这样做,但是对于不同的问题,谁知道呢--见下面的讨论。
下面的所有代码都可以在这里上找到。
你原来的桌子:
CREATE TABLE test
(
name TEXT,
y1990 SMALLINT,
y1991 SMALLINT,
y1992 SMALLINT,
y1993 SMALLINT,
y1994 SMALLINT
);
你的数据:
INSERT INTO test VALUES
('Rex' ,0 , 0 , 1 , 1 , 1),
('Max' , 0 , 0 , 0 , 0 , 1),
('Phil' , 1 , 1 , 1 , 1 , 1);
HiveQL似乎没有支点功能,所以您只需使用好的老式手动方式就可以了。阿基娜指出,有一条“捷径”:
SELECT
name,
CASE
WHEN sc_1990 = 1 THEN 1990 -- the CASE will drop out after first "success"!
WHEN sc_1991 = 1 THEN 1991
WHEN sc_1992 = 1 THEN 1992
WHEN sc_1993 = 1 THEN 1993
WHEN sc_1994 = 1 THEN 1994
END AS score
FROM test
ORDER BY score;
结果:
name m_yr
Phil 1990
Rex 1992
Max 1994
但是,对于较长期的解决方案,并举例说明:
1
值,或因此,最好使用以下方法:
CREATE TABLE toradh -- both "result" and "match" are SQL keywords! - see https://www.drupal.org/docs/develop/coding-standards/list-of-sql-reserved-words, so I used an Irish word!
(
name TEXT,
yr SMALLINT,
score SMALLINT
);
然后:
INSERT INTO toradh
VALUES
('Rex', 1990, 0),
('Rex', 1991, 0),
...
... snipped for brevity
...
检查:SELECT * FROM toradh;
:
结果:
name yr score
Rex 1990 0
Rex 1991 0
Rex 1992 1
Rex 1993 1
Rex 1994 1
Max 1990 0
...
... snipped for brevity
...
因此,您的查询可以编写如下所示:
SELECT
name, MIN(yr) -- , MAX(scor) -- see what happens when you uncomment
FROM toradh
WHERE yr BETWEEN 1990 AND 1994 -- or 1960 AND 2010
AND score = 1
GROUP BY name
ORDER BY MIN(yr);
结果(相同):
name min
Phil 1990
Rex 1992
Max 1994
您会发现,将来编写查询要简单得多,而且您可以以一种更简单的方式对数据提出更复杂的问题。
例如,想象一下,您的查询不是在1990到1994年间,而是在1960到2010年间--它将是巨大的--这样的话,它的大小就会完全相同--只有从参数到参数的年份才会有变化!
当桌子又高又瘦,而不是又矮又胖的时候,桌子会更好!而且,在将来,当你问这样的问题时,你能不能自己摆弄一下你的表格和数据--它能防止为那些试图回答的人重复工作,并且它提供了一个单一的真理来源--帮助我们帮助你!附注:欢迎来到dba.se!
几乎同样重要的是,上面的简化查询假定数据是预先知道的--也就是说,您已经声明:
但是,除了在最琐碎的情况下,通常不能假定已知的值(即使可能相当肯定),所以您只需要使用这样的查询:
SELECT name, 1990 AS yr, sc_1990 AS score FROM test t1
UNION ALL
SELECT name, 1991 AS yr, sc_1991 FROM test t1
UNION ALL
SELECT name, 1992 AS yr, sc_1992 FROM test t1
UNION ALL
SELECT name, 1993 AS yr, sc_1993 FROM test t1
UNION ALL
SELECT name, 1994 AS yr, sc_1994 FROM test t1;
结果:
name yr score
Rex 1990 0
Max 1990 0
Phil 1990 1
Rex 1991 0
...
... snipped for brevity
...
您的查询(考虑到事先不知道这些数据)如下所示:
WITH cte AS
(
SELECT name, 1990 AS yr, sc_1990 AS score FROM test t1
UNION ALL
SELECT name, 1991 AS yr, sc_1991 FROM test t1
UNION ALL
SELECT name, 1992 AS yr, sc_1992 FROM test t1
UNION ALL
SELECT name, 1993 AS yr, sc_1993 FROM test t1
UNION ALL
SELECT name, 1994 AS yr, sc_1994 FROM test t1
)
SELECT
c.name, MIN(c.yr) AS m_yr
FROM cte c
WHERE c.score != 0
GROUP BY c.name
ORDER BY m_yr;
同样的结果-见小提琴。
总之,您最好重构架构!将列名作为数据的一部分,您将数据和元数据混合在一起,这从来都不是很好的实践!
https://dba.stackexchange.com/questions/303218
复制相似问题