我有这样的表:
value1 value2 value3 value4 value5 constant
1 2 3 4 5 2
8 2 8 3 5 2
1 5 3 4 5 3
1 2 6 4 5 3
现在我想做的是,我想在列中找到只有那些列数的总和作为常量字段中给出的值:
例如,如果常量值为2
,则在row1中,
我需要找到value1+value2
的总和。
如果常量中的值为3
,我需要找到总和value 1+ value2 + value3
抱歉英语不好。有什么合适的方法吗?我一直在谷歌搜索它,但找不到合适的方式
答案 0 :(得分:3)
值列固定为1到5?如果不是,则需要生成动态查询。
试试这个:
SELECT
IF(constant = 1, value1,
IF (constant = 2, value1 + value2,
IF (constant = 3, value1 + value2 + value3,
IF (constant = 4, value1 + value2 + value3 + value4, value1 + value2 + value3 + value4 + value5)
)
)
)
FROM tab;
<强>已更新强>
如果我是你,我会这样设计。tbl1(id, constant),
value_tbl1(tbl1_id, column_seq, value);
SELECT SUM(value)
FROM tbl1 t, value_tbl1 v
WHERE t.id = v.tbl1_id
AND column_seq BETWEEN 1 AND tbl1.constant
答案 1 :(得分:2)
<强>简介强>
解决这个问题的正常方法是:选择正确的结构。如果你有24个字段,你需要在SQL中动态循环,那么出错了。此外,您的表没有任何主键(或者您没有提到),这是很糟糕的。
非常重要的注意事项
不管我描述的方式是否有效。由于在MySQL中使用了一些特殊的东西,这仍然是不好的做法。您可以自担风险使用它 - 如果可能的话,再次重新考虑您的结构。
黑客
实际上,你可以使用MySQL INFORMATION_SCHEMA表做一些技巧。通过这个,您可以创建“text”SQL,稍后可以在prepared statement中使用。
我的表
它被称为test
。这是:
+----------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+---------+------+-----+---------+-------+ | value1 | int(11) | YES | | NULL | | | value2 | int(11) | YES | | NULL | | | value3 | int(11) | YES | | NULL | | | value4 | int(11) | YES | | NULL | | | constant | int(11) | YES | | NULL | | +----------+---------+------+-----+---------+-------+
- 我有4
个“值”字段,没有主键列(这会导致麻烦,但我已经解决了这个问题)。现在,我的数据:
+--------+--------+--------+--------+----------+ | value1 | value2 | value3 | value4 | constant | +--------+--------+--------+--------+----------+ | 2 | 5 | 6 | 0 | 2 | | 1 | -100 | 0 | 0 | 1 | | 3 | 10 | -10 | 0 | 3 | | 4 | 0 | -1 | 5 | 3 | | -1 | 1 | -1 | 1 | 4 | +--------+--------+--------+--------+----------+
技巧
它是关于从MySQL中提到的服务模式中选择数据并使用GROUP_CONCAT函数:
select
concat('SELECT CASE(seq) ',
group_concat(groupcase separator ''),
' END AS result FROM (select *, @j:=@j+1 as seq from test cross join (select @j:=0) as initj) as inittest')
from
(select
concat(' WHEN ', rownum, ' THEN ', groupvalue) as groupcase
from
(select
rownum,
group_concat(COLUMN_NAME SEPARATOR '+') as groupvalue
from
(select
*,
@row:=@row+1 as rownum
from test
cross join (select @row:=0) as initrow) as tablestruct
left join
(select
COLUMN_NAME,
@num:=@num+1 as num
from
INFORMATION_SCHEMA.COLUMNS cross join (select @num:=0) as init
where
TABLE_SCHEMA='test' &&
TABLE_NAME='test' &&
COLUMN_NAME!='constant') as struct
on tablestruct.constant>=struct.num
group by
rownum) as groupvalues) as groupscase
- 这会怎么做?实际上,我建议逐步执行它(即将更复杂的层添加到您已经理解的层) - 我怀疑是否有简短的方法来描述正在发生的事情。它不是一个巫术,它是关于从输入条件构造有效的文本SQL。最终结果如下:
SELECT CASE(seq) WHEN 1 THEN value1+value2 WHEN 2 THEN value1 WHEN 3 THEN value3+value2+value1 WHEN 4 THEN value3+value2+value1 WHEN 5 THEN value2+value1+value4+value3 END AS result FROM (select *, @j:=@j+1 as seq from test cross join (select @j:=0) as initj) as inittest
(我没有添加格式,因为SQL是生成的字符串,而不是你自己编写的字符串。)
最后一步
现在怎么办?只需分配:
mysql> set @s=(select concat('SELECT CASE(seq) ', group_concat(groupcase separator ''), ' END AS result FROM (select *, @j:=@j+1 as seq from test cross join (select @j:=0) as initj) as inittest') from (select concat(' WHEN ', rownum, ' THEN ', groupvalue) as groupcase from (select rownum, group_concat(COLUMN_NAME SEPARATOR '+') as groupvalue from (select *, @row:=@row+1 as rownum from test cross join (select @row:=0) as initrow) as tablestruct left join (select COLUMN_NAME, @num:=@num+1 as num from INFORMATION_SCHEMA.COLUMNS cross join (select @num:=0) as init where TABLE_SCHEMA='test' && TABLE_NAME='test' and COLUMN_NAME!='constant') as struct on tablestruct.constant>=struct.num group by rownum) as groupvalues) as groupscase); Query OK, 0 rows affected (0.00 sec) mysql> prepare stmt from @s; Query OK, 0 rows affected (0.00 sec) Statement prepared
- 最后:
mysql> execute stmt;
您将得到以下结果:
+--------+ | result | +--------+ | 7 | | 1 | | 3 | | 3 | | 0 | +--------+
为什么这很糟糕
因为它为整个表生成字符串。即每行 !想象一下,如果你有1000行 - 这将是令人讨厌的。 MySQL在GROUP_CONCAT
:group_concat_max_len中也有限制 - 显然会限制这种方式。
那我为什么这样做?
因为我很好奇是否存在没有额外DDL和隐含重新计算表字段的方法。我找到了,所以把它留在这里。
答案 2 :(得分:1)
正确的做法可能就是这样......
DROP TABLE IF EXISTS variables;
CREATE TABLE variables
(constant_id INT NOT NULL
,sequence_id INT NOT NULL
,value INT NOT NULL
,PRIMARY KEY(constant_id,sequence_id)
);
INSERT INTO variables VALUES
(1,1,1),
(1,2,2),
(1,3,3),
(1,4,4),
(1,5,5),
(2,1,8),
(2,2,2),
(2,3,8),
(2,4,3),
(2,5,5),
(3,1,1),
(3,2,5),
(3,3,3),
(3,4,4),
(3,5,5),
(4,1,1),
(4,2,2),
(4,3,6),
(4,4,4),
(4,5,5);
DROP TABLE IF EXISTS constants;
CREATE TABLE constants
(constant_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,constant INT NOT NULL
);
INSERT INTO constants VALUES (1,2),(2,2),(3,3),(4,3);
SELECT * FROM constants;
+-------------+----------+
| constant_id | constant |
+-------------+----------+
| 1 | 2 |
| 2 | 2 |
| 3 | 3 |
| 4 | 3 |
+-------------+----------+
SELECT * FROM variables;
+-------------+-------------+-------+
| constant_id | sequence_id | value |
+-------------+-------------+-------+
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 3 |
| 1 | 4 | 4 |
| 1 | 5 | 5 |
| 2 | 1 | 8 |
| 2 | 2 | 2 |
| 2 | 3 | 8 |
| 2 | 4 | 3 |
| 2 | 5 | 5 |
| 3 | 1 | 1 |
| 3 | 2 | 5 |
| 3 | 3 | 3 |
| 3 | 4 | 4 |
| 3 | 5 | 5 |
| 4 | 1 | 1 |
| 4 | 2 | 2 |
| 4 | 3 | 6 |
| 4 | 4 | 4 |
| 4 | 5 | 5 |
+-------------+-------------+-------+
SELECT c.constant_id
, SUM(v.value)
FROM constants c
JOIN variables v
ON v.constant_id = c.constant_id
AND v.sequence_id <= c.constant
GROUP
BY c.constant_id;
+-------------+--------------+
| constant_id | SUM(v.value) |
+-------------+--------------+
| 1 | 3 |
| 2 | 10 |
| 3 | 9 |
| 4 | 9 |
+-------------+--------------+