[英]How to set a default row for a query that returns no rows?
如果表中不存在行,我需要知道如何返回默认行。 什么是最好的方法来做到这一点? 我只是从这个特定的表中返回一个列来获取它的值。
编辑:这将是 SQL Server。
Oracle 的一种方法:
SELECT val
FROM myTable
UNION ALL
SELECT 'DEFAULT'
FROM dual
WHERE NOT EXISTS (SELECT * FROM myTable)
或者在 Oracle 中:
SELECT NVL(MIN(val), 'DEFAULT')
FROM myTable
或者在 SqlServer 中:
SELECT ISNULL(MIN(val), 'DEFAULT')
FROM myTable
这些使用MIN()
在没有行时返回NULL
的事实。
如果您的基本查询预计只返回一行,那么您可以使用以下技巧:
select NVL( MIN(rate), 0 ) AS rate
from d_payment_index
where fy = 2007
and payment_year = 2008
and program_id = 18
(Oracle 代码,不确定 NVL 是否适合 SQL Server。)
这将消除 select 查询运行两次并提高性能:
Declare @rate int
select
@rate = rate
from
d_payment_index
where
fy = 2007
and payment_year = 2008
and program_id = 18
IF @@rowcount = 0
Set @rate = 0
Select @rate 'rate'
这个怎么样:
SELECT DEF.Rate, ACTUAL.Rate, COALESCE(ACTUAL.Rate, DEF.Rate) AS UseThisRate
FROM
(SELECT 0) DEF (Rate) -- This is your default rate
LEFT JOIN (
select rate
from d_payment_index
--WHERE 1=2 -- Uncomment this line to simulate a missing value
--...HERE IF YOUR ACTUAL WHERE CLAUSE. Removed for testing purposes...
--where fy = 2007
-- and payment_year = 2008
-- and program_id = 18
) ACTUAL (Rate) ON 1=1
结果
有效率存在
Rate Rate UseThisRate
----------- ----------- -----------
0 1 1
使用的默认费率
Rate Rate UseThisRate
----------- ----------- -----------
0 NULL 0
测试 DDL
CREATE TABLE d_payment_index (rate int NOT NULL)
INSERT INTO d_payment_index VALUES (1)
此代码段使用通用表表达式来减少冗余代码并提高可读性。 这是约翰鲍曼答案的变体。
语法适用于 SQL Server。
WITH products AS (
SELECT prod_name,
price
FROM Products_Table
WHERE prod_name LIKE '%foo%'
),
defaults AS (
SELECT '-' AS prod_name,
0 AS price
)
SELECT * FROM products
UNION ALL
SELECT * FROM defaults
WHERE NOT EXISTS ( SELECT * FROM products );
我想通了,它也应该适用于其他系统。 这是WW答案的变体。
select rate
from d_payment_index
where fy = 2007
and payment_year = 2008
and program_id = 18
union
select 0 as rate
from d_payment_index
where not exists( select rate
from d_payment_index
where fy = 2007
and payment_year = 2008
and program_id = 18 )
使用从默认值到实际值的左连接的一种表扫描方法:
CREATE TABLE [stackoverflow-285666] (k int, val varchar(255))
INSERT INTO [stackoverflow-285666]
VALUES (1, '1-1')
INSERT INTO [stackoverflow-285666]
VALUES (1, '1-2')
INSERT INTO [stackoverflow-285666]
VALUES (1, '1-3')
INSERT INTO [stackoverflow-285666]
VALUES (2, '2-1')
INSERT INTO [stackoverflow-285666]
VALUES (2, '2-2')
DECLARE @k AS int
SET @k = 0
WHILE @k < 3
BEGIN
SELECT @k AS k
,COALESCE(ActualValue, DefaultValue) AS [Value]
FROM (
SELECT 'DefaultValue' AS DefaultValue
) AS Defaults
LEFT JOIN (
SELECT val AS ActualValue
FROM [stackoverflow-285666]
WHERE k = @k
) AS [Values]
ON 1 = 1
SET @k = @k + 1
END
DROP TABLE [stackoverflow-285666]
给出输出:
k Value
----------- ------------
0 DefaultValue
k Value
----------- ------------
1 1-1
1 1-2
1 1-3
k Value
----------- ------------
2 2-1
2 2-2
*SQL解决方案
假设您有一个主键为“id”的评论表。
SELECT * FROM review WHERE id = 1555
UNION ALL
SELECT * FROM review WHERE NOT EXISTS ( SELECT * FROM review where id = 1555 ) AND id = 1
如果表没有 1555 id 的评论,则此查询将提供 id 1 的评论。
假设在config_code
列上有一个具有唯一索引的表config
:
CONFIG_CODE PARAM1 PARAM2
--------------- -------- --------
default_config def 000
config1 abc 123
config2 def 456
此查询返回config1
值的行,因为它存在于表中:
SELECT *
FROM (SELECT *
FROM config
WHERE config_code = 'config1'
OR config_code = 'default_config'
ORDER BY CASE config_code WHEN 'default_config' THEN 999 ELSE 1 END)
WHERE rownum = 1;
CONFIG_CODE PARAM1 PARAM2
--------------- -------- --------
config1 abc 123
这个返回默认记录,因为config3
中不存在config3
:
SELECT *
FROM (SELECT *
FROM config
WHERE config_code = 'config3'
OR config_code = 'default_config'
ORDER BY CASE config_code WHEN 'default_config' THEN 999 ELSE 1 END)
WHERE rownum = 1;
CONFIG_CODE PARAM1 PARAM2
--------------- -------- --------
default_config def 000
与其他解决方案相比,该解决方案只查询一次表config
。
你想返回一整行吗? 默认行需要有默认值还是可以是空行? 您是否希望默认行与相关表具有相同的列结构?
根据您的要求,您可能会执行以下操作:
1) 运行查询并将结果放入临时表(或表变量)中 2)检查临时表是否有结果 3)如果没有,则通过执行类似于此的选择语句(在 SQL Server 中)返回一个空行:
select '' as columnA, '' as columnB, '' as columnC from #tempTable
其中 columnA、columnB 和 columnC 是您的实际列名。
将您的默认值插入到表变量中,然后使用实际表中的匹配项更新此 tableVar 的单行。 如果找到一行,tableVar 将被更新; 如果不是,则保留默认值。 返回表变量。
---=== The table & its data
CREATE TABLE dbo.Rates (
PkId int,
name varchar(10),
rate decimal(10,2)
)
INSERT INTO dbo.Rates(PkId, name, rate) VALUES (1, 'Schedule 1', 0.1)
INSERT INTO dbo.Rates(PkId, name, rate) VALUES (2, 'Schedule 2', 0.2)
这是解决方案:
---=== The solution
CREATE PROCEDURE dbo.GetRate
@PkId int
AS
BEGIN
DECLARE @tempTable TABLE (
PkId int,
name varchar(10),
rate decimal(10,2)
)
--- [1] Insert default values into @tempTable. PkId=0 is dummy value
INSERT INTO @tempTable(PkId, name, rate) VALUES (0, 'DEFAULT', 0.00)
--- [2] Update the single row in @tempTable with the actual value.
--- This only happens if a match is found
UPDATE @tempTable
SET t.PkId=x.PkId, t.name=x.name, t.rate = x.rate
FROM @tempTable t INNER JOIN dbo.Rates x
ON t.PkId = 0
WHERE x.PkId = @PkId
SELECT * FROM @tempTable
END
测试代码:
EXEC dbo.GetRate @PkId=1 --- returns values for PkId=1
EXEC dbo.GetRate @PkId=12314 --- returns default values
如果不存在任何值,这就是我用于获取默认值的方法。
select if ((select count(*) from `tbs`.`replication_status`) > 0, (select rs.`last_replication_end_date` from `tbs`.`replication_status`
rs where rs.`last_replication_start_date` is not null and rs.`last_replication_end_date`
is not null and rs.`table` = '%s' order by id desc limit 1), (select CAST(unix_timestamp(CURRENT_TIMESTAMP(6)) as UNSIGNED))) as ts;
我会用图片来回答..
代码
declare @someTable table ( Pk int primary key , Column1 nvarchar(max) , Column2 nvarchar(max) not null , Column3 nvarchar(max) ) ; with model as ( select y.* from ( select null whatever ) x left join @someTable y on (y.Pk=x.whatever) ) select * from model where ( not exists ( select null from @someTable ) ) union all select * from @someTable
cte model
从表模式生成一行,所有列都设置为null
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.