Syntax error when making psql Tables one-to-many relation - postgresql

I`m trying to create some basic DB for my backend API.
I want a one-to many relation with order and order_products so there can be only one order(id) but there can be more rows in "order_products" with the same "order_id" but i get a syntax error:
syntax error at or near "order"
LINE 2: "order_id" int REFERENCES order(id),
^
and i dont know why (This is in the order_products table).
CREATE TABLE IF NOT EXISTS "customers" (
"id" SERIAL PRIMARY KEY,
"first_name" varchar,
"last_name" varchar,
"username" varchar,
"password" varchar,
"email" varchar UNIQUE,
"is_admin" boolean
);
CREATE TABLE IF NOT EXISTS "address" (
"customer_id" int REFERENCES customers(id),
"zipcode" int,
"country" varchar,
"city" varchar,
"street_name" varchar,
"stree_number" varchar,
"mobile_number" int
);
CREATE TABLE IF NOT EXISTS "products" (
"id" SERIAL PRIMARY KEY,
"item_name" varchar UNIQUE,
"description" text,
"image_url" varchar,
"price" float
);
CREATE TABLE IF NOT EXISTS "order" (
"customer_id" int REFERENCES customers(id),
"id" SERIAL PRIMARY KEY,
"date_of_purchase" date,
"total_price" int
);
CREATE TABLE IF NOT EXISTS "order_products" (
"order_id" int REFERENCES order(id),
"product_id" int REFERENCES products(id),
"quantity" int,
"total_price" int,
UNIQUE(order_id, product_id)
);
CREATE TABLE IF NOT EXISTS "cart" (
"customer_id" int REFERENCES customers(id),
"id" SERIAL PRIMARY KEY,
"date_of_purchase" date,
"total_price" int
);
CREATE TABLE IF NOT EXISTS "cart_products" (
"cart_id" int REFERENCES cart(id),
"product_id" int REFERENCES products(id),
"quantity" int,
"total_price" int,
UNIQUE(cart_id, product_id)
);

order is a reserved keyword, so you need to enclose it always in double quotes:
"order_id" int REFERENCES "order"(id),
In general I recommend to never use double quotes. For that you would need to find a different name for the order table that doesn't require quoting

Related

the PostgreSQL engine does not support Windows

I try to generate golang code using sqlc package but it say "the PostgreSQL engine does not support Windows"
I tried to generate code for insert operation in postgresql for which I used postgresql alpine docker image.
my sql.yaml file is
version: "1"
packages:
- name: "db"
path: "./db/sqlc"
queries: "./db/query/"
schema: "./db/migration/"
engine: "postgresql"
emit_json_tags: true
emit_prepared_queries: false
emit_interface: false
emit_exact_table_names: false
account.sql
-- name CreateAccount: one
INSERT INTO accounts (
owner,
balance,
currency
) VALUES(
$1,$2,$3
) RETURNING *;
and my scema contain
CREATE TABLE "accounts" (
"id" bigserial PRIMARY KEY,
"owner" varchar NOT NULL,
"balance" bigint NOT NULL,
"currency" varchar NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
CREATE TABLE "entries" (
"id" bigserial PRIMARY KEY,
"account_id" bigint NOT NULL,
"amount" bigint NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
CREATE TABLE "transfers" (
"id" bigserial PRIMARY KEY,
"from_account_id" bigint NOT NULL,
"to_account_id" bigint NOT NULL,
"amount" bigint NOT NULL,
"created_at" timestamptz NOT NULL DEFAULT (now())
);
ALTER TABLE "entries" ADD FOREIGN KEY ("account_id") REFERENCES "accounts" ("id");
ALTER TABLE "transfers" ADD FOREIGN KEY ("from_account_id") REFERENCES "accounts" ("id");
ALTER TABLE "transfers" ADD FOREIGN KEY ("to_account_id") REFERENCES "accounts" ("id");
CREATE INDEX ON "accounts" ("owner");
What I am missing?
Regarding #282 sqlc doesn't support PostgreSQL for windows. But you can generate files using docker, as mentioned in the installation guide of sqlc.(link)
docker run --rm -v $(shell pwd):/src -w /src kjconroy/sqlc generate

Postgres create many to many relationship to table with composite primary key

CREATE TABLE "public"."Users" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now()
);
CREATE TABLE "public"."Boards" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) NOT NULL,
"ownerId" SERIAL NOT NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP,
FOREIGN KEY ("ownerId") REFERENCES "public"."Users"(id)
);
CREATE TABLE "public"."Board_Members"(
"userId" SERIAL,
"boardId" SERIAL,
CONSTRAINT board_member_pkey PRIMARY KEY ("userId", "boardId"),
FOREIGN KEY ("userId") REFERENCES "public"."Users"(id),
FOREIGN KEY ("boardId") REFERENCES "public"."Boards"(id)
);
CREATE TABLE "public"."Columns" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) NOT NULL,
"boardId" SERIAL NOT NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP,
FOREIGN KEY ("boardId") REFERENCES "public"."Boards"(id)
);
CREATE TABLE "public"."Cards" (
id SERIAL PRIMARY KEY NOT NULL,
name VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL,
dueDate TIMESTAMP,
"columnId" SERIAL NOT NULL,
"createdAt" TIMESTAMP NOT NULL DEFAULT now(),
"updatedAt" TIMESTAMP,
FOREIGN KEY ("columnId") REFERENCES "public"."Columns"(id),
);
I have these tables. Now I want to have a field called "assignee" in "Cards" table which will be a many-to-many relationship with "userId" from "Board_Members" table just like "Boards" and "Users" have a many-to-maany relationship. How do I do that? Do I create a new table and just reference the "userId" column as FK?
Just add a table with 2 foreign keys.
And because I think you want to switch the cards, from person to person. you could also want to keep track of the played history. See also the first normal form to check if your database is designed right.
https://en.wikipedia.org/wiki/First_normal_form
I hope I answered your question :)

PostgreSQL - How to merge data from multiple rows using join from other tables

I am using postgresql 9.6 and want to merge data from multiple rows into one. I'm using 4 tables(the table format and data cannot be changed)
Tables are-
"id" int4 DEFAULT nextval('product_a_seq'::regclass) NOT NULL,
"name" varchar(255) COLLATE "default",
"organization_id" int4,
"description" text COLLATE "default",
"image" varchar(255) COLLATE "default" DEFAULT 'https://abcd.com'::character varying,
"deleted" bool,
"price" float4,
"currency_id" int4,
CONSTRAINT "product_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."product_asset" (
"id" int4 DEFAULT nextval('product_asset_a_seq'::regclass) NOT NULL,
"product_id" int4,
"asset_type" varchar(255) COLLATE "default",
"asset_url" text COLLATE "default",
"asset_value" text COLLATE "default",
"asset_name" text COLLATE "default",
CONSTRAINT "product_asset_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."user" (
"id" int4 DEFAULT nextval('istar_user_a_seq'::regclass) NOT NULL,
"mobile" varchar COLLATE "default",
"name" varchar(255) COLLATE "default",
"organization_id" int4,
CONSTRAINT "istar_user_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."pipeline_product" (
"pipeline_id" int4 NOT NULL,
"product_id" int4 NOT NULL,
CONSTRAINT "uq_pipeline_product_pipeline_id_product_id" UNIQUE ("pipeline_id", "product_id")
)
For each product there can be multiple assets and pipelines
I want all data grouped according to product.id, here's my initial attempt
SELECT
product. ID AS pid,
product. NAME AS pname,
product.price,
product.currency_id,
product.description,
product_asset.asset_type,
product_asset.asset_url,
product_asset.asset_name,
product_asset.asset_value,
product_asset. ID AS asset_id,
String_agg ( pipeline_product.pipeline_id :: TEXT, ',' ) AS process_id
FROM
product
LEFT JOIN product_asset ON product_asset.product_id = product. ID
AND product_asset.is_active = TRUE
LEFT JOIN pipeline_product ON pipeline_product.product_id = product. ID
WHERE
organization_id IN (
SELECT
"user" .organization_id
FROM
"user"
WHERE
"user" . ID = 218915
)
AND deleted = FALSE
GROUP BY
pid,
product_asset. ID,
product_asset.asset_type,
product_asset.asset_name,
product_asset.asset_url,
product_asset.asset_value
and i get output as:
I need only one entry for the product.id and everything else should be in a single column,
I am using string_agg() function. What am I missing?
I see three issues in your query:
product_asset.asset_url is not unique, use max(product_asset.asset_url)
product_asset.ID is not unique, so you cannot group it. Use min(product_asset.ID) or max(product_asset. ID)
String_agg(pipeline_product.pipeline_id :: TEXT, ',') does not return always the same value, because they are not sorted, You should add ORDER BY pipeline_product.product_id, pipeline_product.pipeline_id.

Postgresql trigger function working but producing duplicates

Three Postgresql tables (Windows V 9.1.3)
The table obx is a dynamic table that recieves data from several machines.
We want to produce an after insert trigger function
The table testcode is a fixed table, which contains values we are trying to match to the obx table. If testcode TestID an integer field is not null, we want to insert the data into a new table finaldata using an after insert trigger on the table obx.
The first trigger works, but it produces duplicate data. The trigger has to contain "LIMIT 3" as one of the machines send three results at a time.
Trying second option using SQL only but not working.
The fields marked XY in the table finaldata are for internal use.
CREATE TABLE "public"."obx" (
"obxID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"RefRange" varchar,
"Flag" varchar,
"FlagOrig" varchar,
"OperatorID" varchar,
"ObsTime" char(14),
"MsgTime" char(14),
"UnixTime" int4,
"Analyzer" varchar,
"Segment" varchar
)
;
CREATE TABLE "public"."testcode" (
"TcodeID" serial primary key,
"Analyzer" varchar,
"Parameter" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" int4
)
;
CREATE TABLE "public"."finaldata" (
"FdataID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"OperatorID" varchar,
"ObsTime" varchar,
"MsgTime" varchar,
"Analyzer" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" varchar,
"XYchar1" varchar,
"XYchar2" varchar,
"XYchar3" varchar,
"XYint1" int4,
"XYint2" int4,
"XYint3" int4,
"XYGuid" uuid
)
;
DECLARE
var INTEGER;
name text;
short text;
id integer;
BEGIN
SELECT count("TestID") from testcode WHERE "testcode"."Parameter" = NEW."Parameter" into var;
IF var > 0 THEN
SELECT "TestName", "ShortTestName", "TestID" from testcode where "Parameter" = NEW."Parameter" Limit 1 into name, short, id;
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT "Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", name, short, id
from obx WHERE "obx"."Parameter" = NEW."Parameter"
LIMIT 3;
END if;
RETURN NEW;
END;
----------------------------
-- Triggers structure for table "public"."obx"
-- ----------------------------
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;
CREATE FUNCTION testcode_matches()
RETURNS TRIGGER AS $meat$
BEGIN
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units", "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT "obx"."Pid", "obx"."Sid", "obx"."SidOrig", "obx"."Parameter", "obx"."Result", "obx"."ResultOrig", "obx"."Units", "obx"."OperatorID", "obx"."ObsTime", "obx"."MsgTime", "obx"."Analyzer", "TestName", "ShortTestName", "TestID"
FROM obx testcode
JOIN obx ON "obx"."Parameter" = "testcode"."Parameter"
WHERE "testcode"."Parameter" = NEW."Parameter"
AND "testcode"."TestID" = NEW."TestID"
;
RETURN NEW;
END;
$meat$
LANGUAGE plpgsql;
----------------------------
-- Triggers structure for table "public"."obx"
-- ----------------------------
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;
It seems you were confusing yourself by giving obx the correlation name "testcode" :
TESTTABLES:
SET search_path='tmp';
DROP TABLE "obx" CASCADE;
CREATE TABLE "obx" (
"obxID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"RefRange" varchar,
"Flag" varchar,
"FlagOrig" varchar,
"OperatorID" varchar,
"ObsTime" char(14),
"MsgTime" char(14),
"UnixTime" int4,
"Analyzer" varchar,
"Segment" varchar
);
DROP TABLE "testcode" CASCADE;
CREATE TABLE "testcode" (
"TcodeID" serial primary key,
"Analyzer" varchar,
"Parameter" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" int4
) ;
DROP TABLE "finaldata" CASCADE;
CREATE TABLE "finaldata" (
"FdataID" serial primary key,
"Pid" varchar,
"Sid" varchar,
"SidOrig" varchar,
"Parameter" varchar,
"Result" varchar,
"ResultOrig" varchar,
"Units" varchar,
"OperatorID" varchar,
"ObsTime" varchar,
"MsgTime" varchar,
"Analyzer" varchar,
"TestName" varchar,
"ShortTestName" varchar,
"TestID" varchar,
"XYchar1" varchar,
"XYchar2" varchar,
"XYchar3" varchar,
"XYint1" int4,
"XYint2" int4,
"XYint3" int4,
"XYGuid" uuid
) ;
Function && trigger:
DROP FUNCTION testcode_matches() CASCADE;
CREATE FUNCTION testcode_matches()
RETURNS TRIGGER AS $meat$
BEGIN
INSERT INTO finaldata ("Pid", "Sid", "SidOrig", "Parameter", "Result", "ResultOrig", "Units"
, "OperatorID", "ObsTime", "MsgTime", "Analyzer", "TestName", "ShortTestName", "TestID")
SELECT ob."Pid", ob."Sid", ob."SidOrig", ob."Parameter", ob."Result", ob."ResultOrig", ob."Units"
, ob."OperatorID", ob."ObsTime", ob."MsgTime", ob."Analyzer"
, tc."TestName", tc."ShortTestName", tc."TestID"
FROM obx ob
JOIN testcode tc ON ob."Parameter" = tc."Parameter"
WHERE ob."Parameter" = NEW."Parameter"
-- AND ob."TestID" = NEW."TestID" -- Column does not exist
AND ob."obxID" = NEW."obxID" -- This appears to be the PK for obx
;
RETURN NEW;
END;
$meat$ LANGUAGE plpgsql;
CREATE TRIGGER finaldata_ins
AFTER INSERT ON obx
FOR EACH ROW
EXECUTE PROCEDURE testcode_matches()
;
TESTDATA:
INSERT INTO testcode ("TestID", "Parameter") VALUES ( 101, 'Fudge');
INSERT INTO obx -- i"obxID" serial primary key,
( "Pid", "Sid" , "Parameter" ) VALUES ('Foo', 'Bar' ,'Fudge' ) ;
SELECT * FROM finaldata;
Also: I am missing a few foreign key constraints. I would expect the testdata to have at least the same keyfields as obx as candidate key. (plus som version/date,Parameter keyfield) It seems your datamodel is not fit to support the data you feed into it.

pgAdmin - When trying to make a foreign key "referencing" gives no options

I have three tables: ModelingAgency.clients, ModelingAgency.models, ModelingAgency.Bookings. All three tables have a primary key column called id.
The table bookings has two columns that reference clients and models. In pgAdmin when I try to create a foreign key in bookings to either clients or models I get the following screens:
What am I overlooking here? I am new to PostgreSQL (This is my first test project with PostgreSQL -- I've always used MySQL and occasionally SQL Server) so it's probably something obvious (I just don't see it).
EDIT: Here is the DDL, as requested:
-- Table: "ModelingAgency.bookings"
-- DROP TABLE "ModelingAgency.bookings";
CREATE TABLE "ModelingAgency.bookings"
(
id integer NOT NULL DEFAULT nextval('"ModelingAgency.Bookings_id_seq"'::regclass),
"clientId" integer NOT NULL,
"modelId" integer NOT NULL,
"time" timestamp with time zone NOT NULL DEFAULT now(),
"location" character varying(100) NOT NULL DEFAULT 'No Location Selected'::character varying,
CONSTRAINT "bookingId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.bookings" OWNER TO "MyBatisTutorial";
-- Table: "ModelingAgency.clients"
-- DROP TABLE "ModelingAgency.clients";
CREATE TABLE "ModelingAgency.clients"
(
id integer NOT NULL DEFAULT nextval('"ModelAgency.clients_id_seq"'::regclass),
"name" character varying(45) NOT NULL,
CONSTRAINT "clientId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.clients" OWNER TO "MyBatisTutorial";
-- Table: "ModelingAgency.models"
-- DROP TABLE "ModelingAgency.models";
CREATE TABLE "ModelingAgency.models"
(
id serial NOT NULL,
"name" character varying(45) NOT NULL,
CONSTRAINT "modelId" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
ALTER TABLE "ModelingAgency.models" OWNER TO "MyBatisTutorial";
Looking into your posted DDL code I see that your table's names are written in wrong way (that causes your issue with pgAdmin):
"ModelingAgency.bookings"
It should be in format "schema"."tableName":
"ModelingAgency"."bookings"
After that Object browser looks like this (probably you need to create schema first using easily pgAdmin or with CREATE SCHEMA SQL statement):
Here is working DDL code (I omitted some things like OIDS and OWNER TO, but that doesn't matter to your case, BTW OIDS are false on default):
DROP TABLE IF EXISTS "ModelingAgency"."bookings";
CREATE TABLE "ModelingAgency"."bookings"
(
id serial,
"clientId" integer NOT NULL,
"modelId" integer NOT NULL,
"time" timestamp with time zone NOT NULL DEFAULT now(),
"location" character varying(100) NOT NULL
DEFAULT 'No Location Selected'::character varying,
CONSTRAINT "bookingId" PRIMARY KEY (id)
);
DROP TABLE IF EXISTS "ModelingAgency"."clients";
CREATE TABLE "ModelingAgency"."clients"
(
id serial,
"name" character varying(45) NOT NULL,
CONSTRAINT "clientId" PRIMARY KEY (id)
);
DROP TABLE IF EXISTS "ModelingAgency"."models";
CREATE TABLE "ModelingAgency"."models"
(
id serial NOT NULL,
"name" character varying(45) NOT NULL,
CONSTRAINT "modelId" PRIMARY KEY (id)
)