通过替换不同的值来对SQL分组

时间:2018-10-29 12:15:37

标签: java sql postgresql

是否可以对数据进行分组,但使用PostgreSQL将不同的值替换为@。还是JAVA可以做得更好,更有生产力?

有些表有下一个数据

 id  name1  f1  f2  f3  f4  f5
  1   lol    0   1   1    0   0
  2   lol    0   1   1    0   0
  3   lol    0   1   1    0   0
  4   kek    1   1   1    1   0
  5   kek    2   1   1    0   0
  6   kek    4   1   1    0   0
  7   kek    3   1   1    0   0

,我需要使用分组的相同数据检索名称,但是不同的数据必须以some char的形式查看 例如:

  name1  f1  f2  f3  f4  f5
  lol    0   1   1   0   0
  kek    @   1   1   @   0

3 个答案:

答案 0 :(得分:2)

demo:db<>fiddle

SELECT 
    name, 
    CASE WHEN COUNT(DISTINCT f1) > 1 THEN '@' ELSE MAX(f1)::text END as f1,
    CASE WHEN COUNT(DISTINCT f2) > 1 THEN '@' ELSE MAX(f2)::text END as f2,
    CASE WHEN COUNT(DISTINCT f3) > 1 THEN '@' ELSE MAX(f3)::text END as f3,
    CASE WHEN COUNT(DISTINCT f4) > 1 THEN '@' ELSE MAX(f4)::text END as f4,
    CASE WHEN COUNT(DISTINCT f5) > 1 THEN '@' ELSE MAX(f5)::text END as f5
FROM
    my_table
GROUP BY name

对于每一列:

  1. 按名称分组
  2. 总计COUNT(DISTINCT)计算不同的值
  3. 计数合计超过一个不同值的所有聚合结果都会产生新字符
  4. 其他给出一个单一值。 (因为您需要由GROUP BY引起的聚合函数。最简单的方法是采用MAXMIN,所以没关系-只有一个值)。由于添加了text类型的值,因此所有其他值都必须转换为同一列类型,因为不允许在一列中获取更多类型。因此,如果您确实有integer值,则最好也将integer值用作您的“标记”值。如果您没有任何负值或类似的值,则负值也许可以做到。

答案 1 :(得分:1)

使用子查询时,您可以尝试使用大小写。

CREATE TABLE T(
  name1 varchar(50),
    f1 int,
   f2  int,
  f3 int, 
  f4 int,
  f5 int
);


INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('lol',0,1,1,0,0);
INSERT INTO T VALUES ('kek',1,1,1,1,0);
INSERT INTO T VALUES ('kek',2,1,1,0,0);
INSERT INTO T VALUES ('kek',4,1,1,0,0);
INSERT INTO T VALUES ('kek',3,1,1,0,0);

查询1

SELECT distinct
name1,
CASE WHEN  
(SELECT COUNT(DISTINCT f1) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f1::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f2) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f2::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f3) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f3::VARCHAR(50) END,
  CASE WHEN  
(SELECT COUNT(DISTINCT f4) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f4::VARCHAR(50) END,
    CASE WHEN  
(SELECT COUNT(DISTINCT f5) cnt
  FROM T tt 
  WHERE t1.name1 = tt.name1) > 1 THEN '@' ELSE t1.f5::VARCHAR(50) END  
FROM T t1 

Results

| name1 | f1 | f2 | f3 | f4 | f5 |
|-------|----|----|----|----|----|
|   kek |  @ |  1 |  1 |  @ |  0 |
|   lol |  0 |  1 |  1 |  0 |  0 |

答案 2 :(得分:1)

此处无需子查询。您可以使用GROUP在单个查询中进行操作。看看:

SELECT
  name1,
  CASE WHEN array_length(array_agg(DISTINCT f1), 1) = 1 THEN min(f1)::text ELSE '@' END AS f1,
  CASE WHEN array_length(array_agg(DISTINCT f2), 1) = 1 THEN min(f2)::text ELSE '@' END AS f2,
  CASE WHEN array_length(array_agg(DISTINCT f3), 1) = 1 THEN min(f3)::text ELSE '@' END AS f3,
  CASE WHEN array_length(array_agg(DISTINCT f4), 1) = 1 THEN min(f4)::text ELSE '@' END AS f4,
  CASE WHEN array_length(array_agg(DISTINCT f5), 1) = 1 THEN min(f5)::text ELSE '@' END AS f5
FROM T
GROUP BY name1;

这是怎么回事:

  1. 行按name1分组
  2. 对于每个组,array_agg函数将返回给定字段的属性数组
  3. 该数组中的重复项被DISTINCT子句删除
  4. array_length函数返回数组中的元素数。由于数组没有重复项,因此它是唯一元素的数量。
  5. 使用CASE语句格式化结果。如果数组具有1个元素,则将其显示(转换为文本)。否则,将显示@

沙箱:https://www.db-fiddle.com/f/3vxfeU8SzRRhtCcTvzj9fG/0