Postgresql

為什麼是“INSERT INTO 表;”語法錯誤?

  • August 3, 2020

我有這個:

   CREATE TABLE people
   (
       id              bigserial,
       timestamp       timestamptz DEFAULT now() NOT NULL,
       PRIMARY KEY     (id)
   );

   CREATE TABLE "personal information"
   (
       id                  bigserial,
       "person id"         bigint NOT NULL,
       timestamp           timestamptz DEFAULT now() NOT NULL,
       "data's timestamp"  timestamptz,
       "field"             text NOT NULL,
       "value"             text,
       PRIMARY KEY         (id),
       FOREIGN KEY         ("person id") REFERENCES people (id) ON UPDATE CASCADE ON DELETE CASCADE
   );

   INSERT INTO people RETURNING id; -- Syntax error.
   INSERT INTO people; -- Syntax error.
   

為什麼我的 INSERTS 會失敗?事實上,“people”表中的所有列都是自動的:該id列是一個 bigserial,並且timestamp始終設置為插入時的目前時間。因此,我不需要指定要插入的任何列,因為它們都是自動的。

那麼為什麼會出現語法錯誤呢?它要我做什麼?這讓我覺得好像我做的不對,但是在“人”表中有一堆“個人數據”欄位將是多餘的,因為這些數據將儲存在“個人資訊”表中。例如,“欄位”可能是“社會安全號碼”或“名字”,所以我只需獲取該“個人 ID”的最新記錄(基於時間戳)來獲取他們的社會安全號碼或名字。

如果我將這些值作為列儲存在“人”中,那將是毫無意義的冗餘,而且每當我將來引入一種新的“個人資訊欄位”時,它都會成為主要的 PITA,因為我必須這樣做在“人”表中添加列。所以我真的希望我的高效和智能(IMO)結構不會與 PostgreSQL 不兼容,我只是缺少一些小的語法細節。

語法規則要求至少指定一個目標列。如果您想讓所有列的預設值“生效”,您可以使用該default values子句。

INSERT INTO people DEFAULT VALUES;

另一種選擇是為一列提供該DEFAULT子句:

insert into people ("timestamp") values (default);

一種方法如下:

CREATE TABLE people
(
   id              bigserial,
   timestamp       timestamptz DEFAULT now() NOT NULL,
   PRIMARY KEY     (id)
);

進而:

INSERT INTO people (timestamptz) VALUES (NOW()) RETURNING id;

似乎一個INSERT子句必須至少有一個值,儘管正如您所指出的,DEFAULT NOW()在這種特殊情況下,它使您的表聲明中的聲明變得多餘!

看來您在 PostgreSQL (+1) 中發現了一個(非常)極端情況錯誤!

更新:

遵循@a_horse_with_no_name 的出色答案,出於展示目的,我已將他的解決方案包含在此處的新小提琴中。

幾點:

  • 你應該(為了你自己的理智)永遠不要使用 SQL 關鍵字作為表或列名
  • 您的 EAV 系統(如 @Martin Smith 所指出的)存在缺陷 - 例如,如果您有一個名為的欄位age_in_years- 您可以將其設為 aSMALLINT並進一步添加CHECK約束(age_in_years >= 0<= 120),然後優化器(通常)可以生成FAR更好的計劃涉及該欄位的任何查詢 - 這幾乎適用於所有欄位,加上事實(已經提到)您的查詢將很快變得****非常麻煩!

ps一如既往,歡迎來到論壇!

引用自:https://dba.stackexchange.com/questions/273058