首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >对于每个元组,获取第一个列的名称,它是非零的。

对于每个元组,获取第一个列的名称,它是非零的。
EN

Database Administration用户
提问于 2021-11-28 08:47:31
回答 1查看 175关注 0票数 1

我在蜂巢里有张桌子,看起来像:

代码语言:javascript
运行
AI代码解释
复制
| Name | 1990 | 1991 | 1992 | 1993 | 1994 |
| Rex  | 0    | 0    | 1    | 1    | 1    |
| Max  | 0    | 0    | 0    | 0    | 1    |
| Phil | 1    | 1    | 1    | 1    | 1    |

对于每一行,我都想得到第一列的名称,它是非零的,所以类似于:

代码语言:javascript
运行
AI代码解释
复制
| Name | Column |
| Rex  | 1992   |
| Max  | 1994   |
| Phil | 1990   |

对于每一行,保证:

  • 最少有一栏"1";及
  • 如果X列为"1",则对于每一列Y> X,Y列也有"1“。
EN

回答 1

Database Administration用户

回答已采纳

发布于 2021-11-28 17:04:24

有一个“琐碎”的解决方案(下面),它假设问题中的保证是有效的--他们今天很可能会这样做,但是对于不同的问题,谁知道呢--见下面的讨论。

下面的所有代码都可以在这里上找到。

你原来的桌子:

代码语言:javascript
运行
AI代码解释
复制
CREATE TABLE test
(
  name TEXT,
  y1990 SMALLINT,
  y1991 SMALLINT,
  y1992 SMALLINT,
  y1993 SMALLINT,
  y1994 SMALLINT
);

你的数据:

代码语言:javascript
运行
AI代码解释
复制
INSERT INTO test VALUES
('Rex'   ,0    , 0    , 1    , 1     , 1),
('Max'  , 0    , 0    , 0    , 0     , 1),
('Phil' , 1    , 1    , 1    , 1     , 1);

HiveQL似乎没有支点功能,所以您只需使用好的老式手动方式就可以了。阿基娜指出,有一条“捷径”:

代码语言:javascript
运行
AI代码解释
复制
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;

结果:

代码语言:javascript
运行
AI代码解释
复制
name    m_yr
Phil    1990
Rex     1992
Max     1994

但是,对于较长期的解决方案,并举例说明:

  • 您可能无法确定给定(或任何)字段中是否存在1值,或
  • 您可能希望在很长一段时间内(比如1960年到2010年)进行查询,如果您被迫按年查询表,那么SQL将相当可怕。

因此,最好使用以下方法:

代码语言:javascript
运行
AI代码解释
复制
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
);

然后:

代码语言:javascript
运行
AI代码解释
复制
INSERT INTO toradh
VALUES
('Rex', 1990, 0),
('Rex', 1991, 0),
...
... snipped for brevity
...

检查:SELECT * FROM toradh;

结果:

代码语言:javascript
运行
AI代码解释
复制
name      yr    score
Rex     1990        0
Rex     1991        0
Rex     1992        1
Rex     1993        1
Rex     1994        1
Max     1990        0
...
... snipped for brevity
...

因此,您的查询可以编写如下所示:

代码语言:javascript
运行
AI代码解释
复制
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);

结果(相同):

代码语言:javascript
运行
AI代码解释
复制
name     min
Phil    1990
Rex     1992
Max     1994

您会发现,将来编写查询要简单得多,而且您可以以一种更简单的方式对数据提出更复杂的问题。

例如,想象一下,您的查询不是在1990到1994年间,而是在1960到2010年间--它将是巨大的--这样的话,它的大小就会完全相同--只有从参数到参数的年份才会有变化!

当桌子又高又瘦,而不是又矮又胖的时候,桌子会更好!而且,在将来,当你问这样的问题时,你能不能自己摆弄一下你的表格和数据--它能防止为那些试图回答的人重复工作,并且它提供了一个单一的真理来源--帮助我们帮助你!附注:欢迎来到dba.se!

几乎同样重要的是,上面的简化查询假定数据是预先知道的--也就是说,您已经声明:

  • 最少有一栏"1";及
  • 如果X列为"1",则对于每一列Y> X,Y列也有"1“。

但是,除了在最琐碎的情况下,通常不能假定已知的值(即使可能相当肯定),所以您只需要使用这样的查询:

代码语言:javascript
运行
AI代码解释
复制
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;

结果:

代码语言:javascript
运行
AI代码解释
复制
name    yr     score
Rex     1990       0
Max     1990       0
Phil    1990       1
Rex     1991       0
...
... snipped for brevity
...

您的查询(考虑到事先不知道这些数据)如下所示:

代码语言:javascript
运行
AI代码解释
复制
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;

同样的结果-见小提琴。

总之,您最好重构架构!将列名作为数据的一部分,您将数据和元数据混合在一起,这从来都不是很好的实践!

票数 1
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/303218

复制
相关文章

相似问题

领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文