我有一个查询,其中包含多个相同类型的列。它们源自left join
的详细信息表 - 多次使用其主表。
根据结果记录,我需要这些列的最大值和最小值。这不应该考虑null
值。
Firebird中有MAX()
和MIN()
个聚合函数。不幸的是,他们只接受一个字段作为参数。
此外,还有maxvalue()
和minvalue()
个函数,它们接受多个参数。不幸的是,当至少一个值为null
时,这些函数会返回null
。我只想忽略null
- 值,并仅在所有值均为null
时返回null
。
以下SQL Fiddle只是一个返回多个列null
的查询示例。由于SQL Fiddle不支持Firebird,我使用MySQL 5.6仅用于演示目的。但最后,我需要Firebird的解决方案。
MySQL 5.6架构设置:
CREATE TABLE Master
(`ID` int)
;
INSERT INTO Master
(`ID`)
VALUES
(1),
(2),
(3)
;
CREATE TABLE Detail
(`MREF` int,
`MYVALUE` int)
;
INSERT INTO Detail
(`MREF`, `MYVALUE`)
VALUES
(1, 1),
(2, 2),
(3, 3)
;
查询1 :
select m.ID, d1.MYVALUE, d2.MYVALUE, d3.MYVALUE
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3
Results :
| ID | MYVALUE | MYVALUE | MYVALUE |
|----|---------|---------|---------|
| 1 | 1 | (null) | (null) |
| 2 | (null) | 2 | (null) |
| 3 | (null) | (null) | 3 |
上述非常简单的示例所需的输出将是:
| ID | MYVALUE | MYVALUE | MYVALUE | MAX | MIN |
|----|---------|---------|---------|-----|-----|
| 1 | 1 | (null) | (null) | 1 | 1 |
| 2 | (null) | 2 | (null) | 2 | 2 |
| 3 | (null) | (null) | 3 | 3 | 3 |
答案 0 :(得分:1)
select m.ID
,nullif(maxvalue(coalesce(d1.MYVALUE,-999999999),coalesce(d2.MYVALUE,-999999999),coalesce(d3.MYVALUE,-999999999)),-999999999) as max_val
,nullif(minvalue(coalesce(d1.MYVALUE, 999999999),coalesce(d2.MYVALUE, 999999999),coalesce(d3.MYVALUE, 999999999)), 999999999) as min_val
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3
select m.ID
,nullif(greatest(coalesce(d1.MYVALUE,-999999999),coalesce(d2.MYVALUE,-999999999),coalesce(d3.MYVALUE,-999999999)),-999999999) as max_val
,nullif(least (coalesce(d1.MYVALUE, 999999999),coalesce(d2.MYVALUE, 999999999),coalesce(d3.MYVALUE, 999999999)), 999999999) as min_val
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3
答案 1 :(得分:0)
maxvalue()
和minvalue()
的等效的Mysql是GREATEST()
和LEAST()
,但只接受两个参数,因此更复杂。但同样的逻辑
select m.ID, d1.MYVALUE, d2.MYVALUE, d3.MYVALUE,
NULLIF(
GREATEST(
GREATEST( COALESCE(d1.MYVALUE,-99999),
COALESCE(d2.MYVALUE,-99999)),
COALESCE(d3.MYVALUE,-99999)
),
-99999
) as max_value,
NULLIF(
LEAST(
LEAST( COALESCE(d1.MYVALUE,99999),
COALESCE(d2.MYVALUE,99999)),
COALESCE(d3.MYVALUE,99999)
),
99999
) as min_value
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3
<强>输出强>
编辑:只有CASE
版本,不需要-99999
虚拟代码,但不会获得5列的预测
<强> SQL Demo 强>
select m.ID, d1.MYVALUE, d2.MYVALUE, d3.MYVALUE,
CASE WHEN d1.MYVALUE IS NULL AND d2.MYVALUE IS NULL AND d3.MYVALUE IS NULL THEN NULL
WHEN d1.MYVALUE IS NULL THEN CASE WHEN d2.MYVALUE IS NULL THEN d3.MYVALUE
WHEN d3.MYVALUE IS NULL THEN d2.MYVALUE
ELSE GREATEST(d2.MYVALUE, d3.MYVALUE)
END
WHEN d2.MYVALUE IS NULL THEN CASE WHEN d1.MYVALUE IS NULL THEN d3.MYVALUE
WHEN d3.MYVALUE IS NULL THEN d1.MYVALUE
ELSE GREATEST(d1.MYVALUE, d3.MYVALUE)
END
WHEN d3.MYVALUE IS NULL THEN CASE WHEN d1.MYVALUE IS NULL THEN d2.MYVALUE
WHEN d2.MYVALUE IS NULL THEN d1.MYVALUE
ELSE GREATEST(d1.MYVALUE, d2.MYVALUE)
END
ELSE GREATEST(GREATEST(d1.MYVALUE,d2.MYVALUE), d3.MYVALUE)
END as t,
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3
答案 2 :(得分:-1)
看看其他答案,我得出结论,必须有封装条款。由于那些产生了复杂的查询,我看了 UDF (用户定义的函数)。
我在FreeAdhocUDF's date functions中找到了F_MAXDATE()
和F_MINDATE()
。不幸的是,如果任何输入参数为maxvalue()
,它们的行为类似于Firebird的内部函数minvalue()
和null
,因为它们返回null
。
由于似乎没有其他UDF符合我的需求,我自己编写了它们。
起初,它似乎是返回模糊值。如果null
传递给他们,则在某些情况下他们会返回17-11-1898 00:00:00
。也就是说,因为Firebird默认情况下不会将null
传递给UDF,而是传递null
- 等效值。如果是TIMESTAMP
,则为17-11-1898 00:00:00
。
要启用null
- 传递给UDF,必须extend the UDFs params declaration with NULL
。
因此,当我将UDF的声明更改为类似的内容时,它起作用了:
DECLARE EXTERNAL FUNCTION MAX_TIMESTAMP
TIMESTAMP NULL,
TIMESTAMP NULL
RETURNS TIMESTAMP
ENTRY_POINT 'MAX_TIMESTAMP' MODULE_NAME 'HKSCommonUDF';
使用我新编写的UDF,我的示例查询看起来像这样(对于TIMESTAMP
值):
select m.ID, d1.MYVALUE, d2.MYVALUE, d3.MYVALUE,
max_timestamp(max_timestamp(d1.MYVALUE, d2.MYVALUE), d3.MYVALUE),
min_timestamp(min_timestamp(d1.MYVALUE, d2.MYVALUE), d3.MYVALUE)
from Master m
left join Detail d1
on d1.MREF = m.ID and d1.MYVALUE = 1
left join Detail d2
on d2.MREF = m.ID and d2.MYVALUE = 2
left join Detail d3
on d3.MREF = m.ID and d3.MYVALUE = 3