【问题标题】:SQLite: INSERT or REPLACE certain columns, don't overwrite others with NULL?SQLite:插入或替换某些列,不要用 NULL 覆盖其他列?
【发布时间】:2018-02-21 11:24:48
【问题描述】:

想象一下我有一张桌子(冰箱),里面有列:(日期(pk)、水果、蔬菜、淀粉、糖果)。这是一个示例行:

date     | fruits | veggies | starches | sweets 
20180220 | melon  | potato  |  pasta   | fudge

我只想用以下内容插入或替换冰箱中的某些列:

> INSERT or REPLACE into refrigerator (date, fruits, veggies, starches) VALUES ("20180220", "apple", "carrot", "bread")

当我这样做时,如果我没有为 (sweets) 指定一个值,它会被 NULL 覆盖。

date     | fruits | veggies | starches | sweets 
20180220 | apple  | carrot  |  bread   | NULL

不替换我指定的值的正确方法是什么?

我确信这是显而易见的事情。请随意嘲笑我。

【问题讨论】:

  • 使用UPDATE? SQL 查询通常非常快,因此您可以在决定使用INSERTUPDATE 之前检查该事物是否存在。
  • 您是否建议使用 INSERT 或 UPDATE 而不是 INSERT 或 REPLACE?如果(日期)是唯一的,我基本上想要一个添加新行的衬线,但如果(日期)不是唯一的,则只替换某些值,而不会将(糖果)列中的有效值归零。
  • @bebocure 您将无法获得该功能,因此只需检查主键是否已经在表中,然后执行插入。 COALESCE 函数将帮助您在 UPDATE 期间保留现有的列值。但是,没有什么神奇的语句可以结合所有这些功能。
  • @PittsburghDBA THIS 是我想听到的。我想我期待魔法。感谢您为回答所做的所有努力。我会看看我是否可以将它放入我正在使用的 Python 脚本中并从那里继续。
  • 我用下面的 UNION ALL 解决方案纠正了自己。我想这毕竟不是那么神奇。只是REPLACE一个人做不到,COALESCE也做不到。

标签: sql sqlite


【解决方案1】:

现在它可以按预期工作,如果该行不存在,它也会插入该行。 如果没有 UNION ALL,它将无法正常运行。第一个 SELECT 使用 COALESCE() 在存在行的情况下保留现有列值。带有 NOT EXISTS 的第二个 SELECT 涵盖了该行不存在的情况,因此它构造一个。因此,UNION ALL 只返回 1 行:来自现有行的“合并”行或全新行。然后,REPLACE INTO 通过主键将这个合并/创建的行替换回表中。

CREATE TABLE refrigerator
  (
  date TEXT(8) NOT NULL PRIMARY KEY
  , fruits TEXT(50) NULL
  , veggies TEXT(50) NULL
  , starches TEXT(50) NULL
  , sweets TEXT(50) NULL
  );

INSERT INTO refrigerator (date, fruits, veggies, starches, sweets)
VALUES ("20180220", "melon", "potato", "pasta", "fudge");

REPLACE INTO refrigerator (date, fruits, veggies, starches, sweets)
SELECT
  date
  , COALESCE("apple", fruits) as fruits
  , COALESCE("carrot", veggies) as veggies
  , COALESCE("bread", starches) as starches
  , COALESCE(NULL, sweets) as sweets
 FROM
   refrigerator
 WHERE
   date = "20180220"
UNION ALL
SELECT
  T.date, T.fruits, T.veggies, T.starches, T.sweets
FROM
(
SELECT
  "20180220" as date
  , "apple" as fruits
  , "carrot" as veggies
  , "bread" as starches
  , NULL as sweets
) AS T
WHERE
  NOT EXISTS (SELECT * FROM refrigerator AS R WHERE R.date = T.date);

SELECT date, fruits, veggies, starches, sweets FROM refrigerator;

这是一个 SQL Fiddle:Refrigerator SQL Fiddle

【讨论】:

  • 我没有足够的代表来支持你,但我将你标记为答案,除非其他人知道另一种处理方式。非常感谢您的时间和精力。你就是那个男人。
  • 谢谢!我只是用 REPLACE INTO 让你做得更好。
  • @bebocure 请记住,如果您没有具有相同 date 值的现有行 - 您每次都必须将其“插入”到数据库中。
  • @PittsburghDBA 只需将SELECT date 更改为SELECT "20180220",你也得到了我的投票 :)
  • @PittsburghDBA 查看我的解决方案 - 我的问题是否过于复杂?
【解决方案2】:

我用两行代码解决了这个问题。

UPDATE refrigerator SET fruits='apple', veggies='carrot', starches='bread' WHERE date='20180220';

然后

INSERT or IGNORE INTO refrigerator (fruits, veggies, starches) VALUES ("apple", "carrot", "bread");

我的想法是倒退的,这可能会使这里的答案过于复杂。如果存在带有(日期)的行,我首先更新特定列。如果不存在,下一行将插入一个包含所需信息的新行 - 如果存在则忽略它。

这种方式会不会出现任何并发症?我已经对其进行了测试,到目前为止一切正常。

【讨论】:

  • 这样更直接。最初的要求是一次性完成,所以这就是你得到的。
  • 您在技术上仍然回答正确。答案是你的。我找到了一种在我的脚本中使它成为两行的方法,而不必将其保留为单行。再次感谢@PittsburghDBA。
  • 很高兴与您合作!
【解决方案3】:

要更新现有数据,请使用更新

https://www.tutorialspoint.com/sqlite/sqlite_update_query.htm

将水果列更新为苹果使用的示例

更新 refigerator set fruits = 'Apple' where YOURWHERECLAUSEHERE

至于如果您不提供任何内容,则插入期望插入的内容?该程序不会读懂你的想法。

【讨论】:

  • 我不是反对者——澄清一下,最好用 UPDATE 简单地遍历每一列?我真的希望有一种方法可以插入新的(日期),但如果(日期)是重复的则替换/更新,并且只更改列出的值而不用单个命令清空糖果列。
  • @bebocure 你的问题很好。 "我想插入或替换仅某些列..."
  • 我肯定误解了这个问题。对不起。
  • 我也是!我忽略了“插入”部分,然后挂断了“某些列”。
  • @JoelLibby 我的解决方案本质上就是您的解决方案。只是想谢谢你。如果我有 15 个代表,我会给你一个真正的支持。 :)
猜你喜欢
  • 1970-01-01
  • 2020-01-04
  • 2015-05-11
  • 1970-01-01
  • 2017-03-01
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
相关资源
最近更新 更多