如果表中存在某些值,如何将值设置为“1”,否则将值设置为“0”?

How can I set a value to '1' if certain values exist in a table and set a value to '0' otherwise?

提问人:Juan Daniel 提问时间:11/14/2023 更新时间:11/14/2023 访问量:54

问:

我有一个名为 Books 的数据库,该数据库有一个名为 PrimaryBooks 的表,其中包含以下数据:

Title            Pages  DateOfRelease
Sapiens          572    1987-01-20
Black Swan       852    2004-07-14
1984             429    1949-12-03
Influence        1582   2017-06-17
Freakonomics     826    2014-11-26
The Alchemist    371    2001-02-07
Quiet            639    2016-08-29
Blink            198    2022-04-11
The Art of War   2485   1772-09-10

该数据库还有另一个名为 SECONDARYBOOKS 的表,其中包含以下数据(它们相似。但是,此表还有两列,分别称为 COLOR 和 PRICE。其他列的名称与第一个表中的名称相同,但采用 Caps 形式,虽然列中的许多数据与其他表相同,但某些值略有不同):

COLOR    PRICE  TITLE           PAGES  DATEOFRELEASE
Green    17     Sapiens         834    1987-01-20
Black    25     Black Swan      852    2004-07-14
Gray     28     1984            429    1949-12-03
Orange   12     Influence       1582   2018-05-16
Red      31     Freakonomics    826    2014-11-26
White    37     The Alchemist   371    2001-02-07
Cyan     10     Meditations     1004   2016-08-29
Blue     18     Deep Work       624    2023-01-12
Yellow   29     The Art of War  2485   1672-09-10

我想做的是在表 SECONDARYBOOKS(必须称为 status)中添加一个新列,它将显示 0 或 1。如果行中的数据与第一个表中的数据完全相同,则显示 1(COLOR 和 PRICE 除外,因为第一个表没有该数据),如果不是,则显示 0。这意味着该表最终必须如下所示:

COLOR    PRICE  TITLE           PAGES  DATEOFRELEASE  STATUS
Green    17     Sapiens         834    1987-01-20     0
Black    25     Black Swan      852    2004-07-14     1
Gray     28     1984            429    1949-12-03     1
Orange   12     Influence       1582   2018-05-16     0
Red      31     Freakonomics    826    2014-11-26     1
White    37     The Alchemist   371    2001-02-07     1
Cyan     10     Meditations     1004   2016-08-29     0
Blue     18     Deep Work       624    2023-01-12     0
Yellow   29     The Art of War  2485   1672-09-10     0

我想知道我怎样才能做到这一点。

我尝试编写以下查询:

SELECT CASE WHEN PB1.Title = SB.TITLE THEN
    CASE WHEN PB2.Pages = SB.PAGES THEN
        CASE WHEN SUBSTRING(CONVERT(varchar(15), PB3.DateOfRelease, 112), 1, 8) = SUBSTRING(CONVERT(varchar(15), SB.DATEOFRELEASE, 112), 1, 8) THEN
            '1'
        ELSE
            '0'
        END
    ELSE
        0'
    END
ELSE
    '0'
END
AS STATUS
FROM SECONDARYBOOKS SB
LEFT JOIN PrimaryBooks PB1 ON PB1.Title = SB.TITLE
LEFT JOIN PrimaryBooks PB2 ON PB2.Pages = SB.PAGES
LEFT JOIN PrimaryBooks PB3 ON PB3.DateOfRelease = SB.DATEOFRELEASE
GROUP BY SB.COLOR, SB.PRICE, SB.TITLE, SB.PAGES, SB.DATEOFRELEASE, PB1.Title, PB2.Pages, PB3.DateOfRelease

但是,当我执行此查询时,它永远不会停止尝试执行。它被卡住了。

SQL 服务器 SSMS

评论

0赞 Peter B 11/14/2023
我在查询中没有看到任何可能导致它永远运行的内容。也许是锁定问题,由同时运行的其他东西引起,但仅此而已(据我所知)。
0赞 Yitzhak Khabinsky 11/14/2023
在提出问题时,您需要提供一个最小的可重现示例:(1) DDL 和示例数据填充,即 CREATE 表和 INSERT T-SQL 语句。(2) 需要执行的操作,即逻辑和代码尝试在 T-SQL 中实现它。(3) 期望的输出,基于上面 #1 中的示例数据。(4) 您的 SQL Server 版本 (SELECT @@version;)。

答:

0赞 Yitzhak Khabinsky 11/14/2023 #1

请尝试以下解决方案。

SQL算法

-- DDL and sample data population, start
DECLARE @tbl_books TABLE (Title VARCHAR(50), Pages INT, DateOfRelease DATE);
INSERT @tbl_books (Title, Pages, DateOfRelease) VALUES
('Sapiens',         572 , '1987-01-20'),
('Black Swan',      852 , '2004-07-14'),
('1984',            429 , '1949-12-03'),
('Influence',       1582, '2017-06-17'),
('Freakonomics',    826 , '2014-11-26'),
('The Alchemist ',  371 , '2001-02-07'),
('Quiet',           639 , '2016-08-29'),
('Blink',           198 , '2022-04-11'),
('The Art of War',  2485, '1772-09-10');

DECLARE @tbl_secondarybooks TABLE (COLOR VARCHAR(20), PRICE INT, Title VARCHAR(50), Pages INT, DateOfRelease DATE);
INSERT @tbl_secondarybooks (COLOR, PRICE, Title, Pages, DateOfRelease) VALUES
('Green',   17, 'Sapiens',          834 ,   '1987-01-20'),
('Black',   25, 'Black Swan',       852 ,   '2004-07-14'),
('Gray',    28, '1984',             429 ,   '1949-12-03'),
('Orange',  12, 'Influence',        1582,   '2018-05-16'),
('Red',     31, 'Freakonomics',     826 ,   '2014-11-26'),
('White',   37, 'The Alchemist',    371 ,   '2001-02-07'),
('Cyan',    10, 'Meditations',      1004,   '2016-08-29'),
('Blue',    18, 'Deep Work',        624 ,   '2023-01-12'),
('Yellow',  29, 'The Art of War',   2485,   '1672-09-10');
-- DDL and sample data population, end

SELECT sb.*, status = 1 
FROM @tbl_secondarybooks AS sb
INNER JOIN @tbl_books AS b ON (sb.Title = b.Title AND sb.Pages = b.Pages AND sb.DateOfRelease = b.DateOfRelease)
UNION ALL
SELECT sb.*,  status = 0 
FROM @tbl_secondarybooks AS sb
LEFT OUTER JOIN @tbl_books AS b ON (sb.Title = b.Title AND sb.Pages = b.Pages AND sb.DateOfRelease = b.DateOfRelease)
WHERE b.Title IS NULL;

输出

颜色 价格 标题 页面 DateOfRelease 地位
25 黑天鹅 852 2004-07-14 1
灰色 28 1984 429 1949-12-03 1
31 怪胎经济学 826 2014-11-26 1
37 炼金术士 371 2001-02-07 1
绿 17 智人 834 1987-01-20 0
12 影响 1582 2018-05-16 0
青色 10 冥想 1004 2016-08-29 0
18 深度工作 624 2023-01-12 0
黄色 29 孙子兵法 2485 1672-09-10 0
0赞 T N 11/14/2023 #2

我不确定你为什么要尝试做三个单独的连接。如果执行了,它将有效地计算出“一些主要书籍具有匹配的标题,一些主要书籍具有匹配的页数,并且某些主要书籍具有匹配的发布日期 - 不一定是同一本书”。我猜你希望所有的东西都与一本主要书籍相匹配。

我希望您想要的是一个测试,它是将状态标志设置为 1 或 0 的表达式的一部分。EXISTS()CASE

我也不确定为什么在比较似乎已经是日期值的内容之前要进行日期到字符串的转换。如果发布日期列已是 DATE 类型(或具有 00:00:00 时间成分的 DATETIME 类型),则无需进行该转换。

假设您已将该列添加到表中,则可以使用以下更新。statusSECONDARYBOOKS

UPDATE SB
SET status = CASE WHEN EXISTS(
        SELECT *
        FROM PrimaryBooks PB
        WHERE PB.Title = SB.TITLE
        AND PB.Pages = SB.PAGES
        AND PB.DateOfRelease = SB.DATEOFRELEASE
    ) THEN 1 ELSE 0 END
FROM SECONDARYBOOKS SB

结果:

颜色 价格 标题 页面 发布日期 地位
绿 17 智人 834 1987-01-20 0
25 黑天鹅 852 2004-07-14 1
灰色 28 1984 429 1949-12-03 1
12 影响 1582 2018-05-16 0
31 怪胎经济学 826 2014-11-26 1
37 炼金术士 371 2001-02-07 1
青色 10 冥想 1004 2016-08-29 0
18 深度工作 624 2023-01-12 0
黄色 29 孙子兵法 2485 1672-09-10 0

有关演示,请参阅此 db<>fiddle

评论

0赞 Juan Daniel 11/15/2023
谢谢。你的回答解决了我的问题。连接确实不是必需的,而该查询正是我需要的。