postgres sql returns no row - sql

I have 3 followings tables:
CREATE TABLE public.a
(
id bigint NOT NULL DEFAULT nextval('a_id_seq'::regclass),
CONSTRAINT a_pkey PRIMARY KEY (id)
)
CREATE TABLE public.b
(
id bigint NOT NULL DEFAULT nextval('b_id_seq'::regclass),
fkid bigint,
CONSTRAINT b_pkey PRIMARY KEY (id),
CONSTRAINT b_fkid_fkey FOREIGN KEY (fkid)
REFERENCES public.a (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
CREATE TABLE public.history
(
id bigint NOT NULL DEFAULT nextval('history_id_seq'::regclass),
CONSTRAINT history_pkey PRIMARY KEY (id)
)
As you can see, the table A has 1 to many relationship with table B. The history table keeps track of logical time inside the app. The following query:
WITH main_q AS (
SELECT
a.id
FROM a
LEFT JOIN b ON a.id = b.fkid
)
SELECT main_q.id,
max(history.id) as as_of
FROM main_q,history
GROUP BY
main_q.id
Returns no rows, even if tables A contains rows, because History table is empty. However, as soon as I add at least 1 row in history table, the query works.
Could someone please explain how I should modify my query so that it returns rows even if history is empty (as long as table A contains rows) ? I would expect to receive a NULL value in as_of column or 0. I tried COALESCE(max(history.id,0)) but this doesn't work either, well, because no rows in history
EDIT Example:
Table A content:
id
1
2
Table B content:
id, fkid
1, 2
2, 2
Table History content:
<empty>

The issue is the query below
SELECT main_q.id,
max(history.id) as as_of
FROM main_q,history
GROUP BY
main_q.id
Why not try a left join, you may have nothing to join, you can try something below
SELECT main_q.id,
max(history.id) as as_of
FROM main_q left join history on 1=1
GROUP BY
main_q.id

If I am not wrong, you are performing a cartesian product between main_q and history, because you haven't a predicate to join these 2 tables.
Likely, when you are performing this cartesian product, if the second table (history) is empty, the cartesian product returns nothing. As soon as you have 1 record in history, you will get data from Main_q. However, if you have more than 1 record in history, you will start to get duplicate data because of the cartesian product.

Related

How do i Update data in table from other table with condition

i have 2 tables and both has one column as a primary and foreign key. i have to update one table column which is empty but the primary table has the values which needs to be updated here. how do i update that particular column by referencing those columns of primary table in foreign-key table?
Table 1 - Primary -Column list
SI.No (PrimaryKey)
UpdateTime
StudentDetail
table 2 - Foreign - Column list
SI.No(ForeignKey)
UpdateTime
BatchCode
Table 2 of updateTime is empty for some students due to some reason. I need to get the update time from table 1 of those empty students and update it to table 2. how do i do this?? using postgress i am.
In Postgres, you can use a FROM clause to reference another table:
update table2 t2
set updatetime = t1.updatetime
from table1 t1
where t1.sl_no = t2.sl_no and t2.updatetime is null;

Query for column key when foreign key is absent in another table postgresql

We have a PostgreSQL database which has a table with a foreign key reference to the primary key of another table like below
Table A
a_key
b_key
when_
Table B
b_key
There was a bug in our code where we removed rows from Table B but did not remove the entries in Table A that were associated with those rows. I am trying to right a query to find all of the primary keys from Table A which have a "b_key" value that does not exist in Table B, I also added a time restriction to the query. My query is below but it is not returning any results. Can anyone see an issue with the query? Is it not done correctly?
select a_key
from A left join B b on a.b_key = b.b_key
where b.b_key is null and A.when_ < '2017-03-13 00:00:00.0'::timestamp
try this first
SELECT
a_key
FROM A
where not exists (
select b_key from B where B.b_key = A.b_key)

Best way to delete duplicate rows in an intersection table based on foreign key column

I'm looking for a way to delete dupicate rows from an intersection table based on a foreign key from one of the tables from the opposite ends of the intersection table. For the sake of clarity, I'll say based on a foreign key value from the intersection table on the left 'tableA'.
CREATE TABLE tableA
(
link varchar(64) NOT NULL PRIMARY KEY,
name varchar(64) NOT NULL
)
CREATE TABLE tableB
(
link varchar(64) NOT NULL PRIMARY KEY,
name varchar(64) NOT NULL
)
CREATE TABLE tableA_AND_tableB--Intersection Table
(
link varchar(64) NOT NULL PRIMARY KEY,
LtableA varchar(64) references tableA(link),
LtableB varchar(64) references tableB(link)
)
Basically, I want to delete all duplicate rows in the intersection table based on the 'LtableA' foreign key field. For instance: Say I have 20 duplicates of 'LtableA = id20140722' in 'tableA_AND_tableB', how do I go about deleting all the rows matching the value 'id20140722' in 'tableA_AND_tableB' without affecting anything else?
Hope my question makes sense.
Delete from tableA_AND_tableB where LtableA = 'id20140722'
This will remove all rows from that table sepcifically with that ID. Alternatively you can see this question for something that will delete all duplicates. Though that answer will keep either the first or last duplicate.
If you want to delete duplicates but still keep one distinct copy of each row:
WITH t AS (
SELECT ROW_NUMBER() OVER(PARTITION BY LtableA, LtableB ORDER BY link) row_num
FROM tableA_AND_tableB
)
DELETE
FROM t
WHERE row_num > 1
AND LtableA = 'id20140722'

How to make an index with an optional FK?

##Original question##
So the business model, which I didn't create, have an optional relationship (as in ER model). It's been a while since I've worked DB so I might be forgetting something. Currently the FK (Foreign Key) of the 1st table point to the PK (Primary Key) of the 2nd table, which is an ID ; I don't recall the term but it's the "fake" one, not the "real" one used by the RDBMS (Relational Database Management System). For simplicity, let's imagine there's only 2 tables.
Currently I'm having nulls in the FK column/attribute when there's no need for the optional relation. When there is an item in that column, I want the full advantages, checking if there's a matching item at the other side of the relationship, where the FK point to (2nd table), also triggers (although there are currently none) and other validations. I was satisfied up to not long ago when I realized I didn't want a duplicate on the important parts of the 1st table, so I wanted to create an unique key but it seems a key cannot be created which include a column/attribute that might contain null. So far there's 2 solutions proposed to me although I understand neither.
The 1st was that I'd put defaults, 0 for digit-based types and an empty string ('') for character-based types. What I don't get for that is that the 2nd table already has a row/tuple with a corresponding value (0). If I was to shift the current rows to not have a row with the default, I assume I then would put in the corresponding content a default too, in my case it's a character-based type. So the "cost" of enabling an index would be to make a multitude of useless joins then a multitude of useless merges by the software, in my case the database section of an office suite, Apache OpenOffice Base. This seem like a lot of added processing and it seem to me some kind of trigger, along with my current design, would be better.
The 2nd was to make a "linked" table (his/her term), a many-to-many relationship but I thought those were only for entries that had more than 1 possible relationship ; that having 0-1 relationship would not use it. And anyway, I'd still be confronted with the same problem, where there would not need to have an entry in that "linked" table. IIRC, the 2 "sides" of such table must contain valid candidate keys.
So the 1-1 relationship is already implemented for the cases where the business model do have the need for that option, with the current non-null entries in the FK. Now I just have to implement a method for the cases when the business model do not need the optional part, to allow for a 0-1 relationship, for the current null entries in the FK while not allowing duplicates.
##fredt request##
This now contain the 3rd example.
The followind sub-section contain a semi-SQL export from Apache OpenOffice Base using the command SCRIPT 'PATH\TO\NAME.sql'. The original file, along with its export, and its non-exported queries, are on How to make an index with an optional FK? example 3.
I'd like a unique key on the 3 columns/attributes ID_to_part1, model_number & ID_to_part2 ; however the original question, in the previous section, show HSQLDB version 1.8.0.10 won't allow a null to be contained in a column which is part of a unique key.
###HSQLDB export###
Producing some kind of SQL ; including non-standard statements.
SET DATABASE COLLATION "Latin1_General"
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE CACHED TABLE "Table1"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"ID_to_part1" INTEGER NOT NULL,"model_number" VARCHAR_IGNORECASE(3) NOT NULL,"ID_to_part2" INTEGER)
CREATE CACHED TABLE "Table2"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"content" VARCHAR_IGNORECASE(1) NOT NULL)
CREATE CACHED TABLE "Table3"("ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,"content" VARCHAR_IGNORECASE(1) NOT NULL)
ALTER TABLE "Table1" ADD CONSTRAINT SYS_FK_87 FOREIGN KEY("ID_to_part1") REFERENCES "Table3"("ID") ON DELETE CASCADE ON UPDATE CASCADE
ALTER TABLE "Table1" ADD CONSTRAINT SYS_FK_90 FOREIGN KEY("ID_to_part2") REFERENCES "Table2"("ID") ON DELETE SET NULL ON UPDATE CASCADE
ALTER TABLE "Table1" ALTER COLUMN "ID" RESTART WITH 15
ALTER TABLE "Table2" ALTER COLUMN "ID" RESTART WITH 2
ALTER TABLE "Table3" ALTER COLUMN "ID" RESTART WITH 4
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 0 MILLIS
SET SCHEMA PUBLIC
INSERT INTO "Table1" VALUES(0,0,'123',0)
INSERT INTO "Table1" VALUES(1,1,'456',NULL)
INSERT INTO "Table1" VALUES(2,2,'789',0)
INSERT INTO "Table1" VALUES(3,0,'012',1)
INSERT INTO "Table1" VALUES(6,3,'345',NULL)
INSERT INTO "Table1" VALUES(7,1,'678',1)
INSERT INTO "Table1" VALUES(8,0,'123',NULL)
INSERT INTO "Table1" VALUES(9,0,'123',1)
INSERT INTO "Table1" VALUES(10,1,'456',0)
INSERT INTO "Table1" VALUES(11,1,'456',1)
INSERT INTO "Table1" VALUES(12,1,'456',0)
INSERT INTO "Table1" VALUES(13,1,'123',NULL)
INSERT INTO "Table1" VALUES(14,1,'123',0)
INSERT INTO "Table2" VALUES(0,'B')
INSERT INTO "Table2" VALUES(1,'E')
INSERT INTO "Table3" VALUES(0,'A')
INSERT INTO "Table3" VALUES(1,'C')
INSERT INTO "Table3" VALUES(2,'D')
INSERT INTO "Table3" VALUES(3,'F')
It seem queries weren't exported, here they are followed by their results
###Query1###
Joined main table:
SELECT "Table1"."ID", "Table3"."content" AS "Table3_content", "Table1"."model_number", "Table2"."content" AS "Table2_content"
FROM "Table1"
LEFT OUTER JOIN "Table2" ON "Table1"."ID_to_part2" = "Table2"."ID"
LEFT OUTER JOIN "Table3" ON "Table1"."ID_to_part1" = "Table3"."ID"
ORDER BY "ID" ASC
Result in:
ID Table3_content model_number Table2_content
0 A 123 B
1 C 456
2 D 789 B
3 A 012 E
6 F 345
7 C 678 E
8 A 123
9 A 123 E
10 C 456 B
11 C 456 E
12 C 456 B
13 C 123
14 C 123 B
###Query2###
The rows/tuples which 2 first part of the unique index could "break" the desired unique index should the 3rd also match. In other words, other rows aren't a threat (Query1 minus Query2).
SELECT *
FROM "Table1"
-- It seem HSQLDB won't support tuples as in WHERE (col1, col2) IN ( SELECT col1, col2 FROM
WHERE "ID_to_part1" IN (
SELECT "ID_to_part1"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number"
HAVING COUNT(*) > 1
) AND "model_number" IN (
SELECT "model_number"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number"
HAVING COUNT(*) > 1
)
ORDER BY "ID_to_part1" ASC, "model_number" ASC, "ID_to_part2" ASC, "ID" ASC
Result in:
ID ID_to_part1 model_number ID_to_part2
8 0 123
0 0 123 0
9 0 123 1
13 1 123
14 1 123 0
1 1 456
10 1 456 0
12 1 456 0
11 1 456 1
###Query3###
The rows/tuples which would "break" the desired unique index.
SELECT "Table1".*
FROM "Table1"
JOIN (
SELECT "ID_to_part1", "model_number", "ID_to_part2"
FROM "Table1"
GROUP BY "ID_to_part1", "model_number", "ID_to_part2"
HAVING COUNT(*) > 1
) AS "non_unique_model"
ON "Table1"."ID_to_part1"="non_unique_model"."ID_to_part1"
AND "Table1"."model_number"="non_unique_model"."model_number"
AND "Table1"."ID_to_part2"="non_unique_model"."ID_to_part2"
ORDER BY "ID_to_part1" ASC, "model_number" ASC, "ID_to_part2" ASC, "ID" ASC
Result in:
ID ID_to_part1 model_number ID_to_part2
10 1 456 0
12 1 456 0
###Beautified important tables schema###
CREATE CACHED TABLE "Table1"(
"ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
"ID_to_part1" INTEGER NOT NULL,
"model_number" VARCHAR_IGNORECASE(3) NOT NULL,
"ID_to_part2" INTEGER
)
CREATE CACHED TABLE "Table2"(
"ID" INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,
"content" VARCHAR_IGNORECASE(1) NOT NULL
)
Welcome to SO! I find your question a little hard to read.
EDIT:
CREATE TABLE table1 (
id INTEGER NOT NULL PRIMARY KEY,
data1 INTEGER NOT NULL
);
CREATE TABLE table2 (
id INTEGER NOT NULL PRIMARY KEY REFERENCES table1(id),
data2 INTEGER NOT NULL
);
There are records in table1. For each record in table1, there is zero or one corresponding record in table2.
This pattern is similar to table inheritance.
Further explanation:
This would allow you to have to following data.
id data1 id data2
---------- ---------
0 1234 0 42
1 5678 2 57
2 9012
See that the records in table1 with ids 0 and 2 have corresponding records in table2. The record with id 1 does not.
P.S.
Note that you also could combine things into one table. Whether this is advisable depends on your situation.
CREATE TABLE table1 (
id INTEGER NOT NULL PRIMARY KEY,
data1 INTEGER NOT NULL,
data2 INTEGER NULL
);
I wanted to create an unique key but it seems a key cannot be created
which include a column that might contain null.
My understanding is that you have a FK on which you want to build an index on to enhance performance and that FK may contain nulls (as in #Paul Draper's solution).
I am no expert in HSQLDB, but the user guide, under the Constraints section says:
"Since version 1.7.2 the behaviour of UNIQUE constraints and indexes with respect to NULL values has changed to conform to SQL standards. A row, in which the value for any of the UNIQUE constraint columns is NULL, can always be added to the table. So multiple rows can contain the same values for the UNIQUE columns if one of the values is NULL."
I understand this to mean that you can build an index on the FK in version 1.7.2 of the database even if the column conain rows with the FK value is Null.
Your question was:
I didn't want a
duplicate on the important parts of the 1st table, so I wanted to
create an unique key but it seems a key cannot be created which
include a column that might contain null.
You don't want a duplicate on the "important parts" in Table1 but it is not clear which parts must be unique. Assuming the "important parts" are some of these three columns:
"ID_to_part1" INTEGER,"model_number" VARCHAR_IGNORECASE(3) NOT NULL,"ID_to_part2" INTEGER
A) If you create a unique constraint on "model_number", which is by definition NOT NULL:
CONSTRAINT UNIQUE ("model_number")
Then model_number values are unique but two different models can have the same ID_to_part1
B) In addition to (A) you can have this constraint:
CONSTRAINT UNIQUE ("model_number", "ID_to_part1")
Then each model_number will correspond to a unique ID_to_part1. If you don't have NOT NULL on ID_to_part1, then it can contain NULL for those model_number values that do not have an extra part.
C) In addition to (A) you can have this:
CONSTRAINT UNIQUE ("model_number", "ID_to_part2")
Which has the same effect as (B) but for the ID_to_part2 column.
Your SELECT statement is correct. It shows all models with any optional information they may have.
In short, you can have a UNIQUE constraint on columns that can have NULL in them. But the UNIQUE constraint on model_number is also required.
Edit:
The OP has edited the question again with the requirement that "model_number" is not unique, only the three columns together are unique while some of them can store NULL and the NULL cannot be repeated. This is not possible to achieve with HSQLDB 1.8. In HSQLDB 2.x there is a setting for SET DATABASE SQL UNIQUE NULLS which can be changed to FALSE to allow this. In this case only one UNIQUE constraints on the three columns is needed.

Set based insert into two tables with 1 to 0-1 relation

I have two tables, the first has a primary key that is an identity, the second has a primary key that is not, but that key has a foreign key constraint back to the first table's primary key.
If I am inserting one record at a time I can use the Scope_Identity to get the value for the pk just inserted in table 1 that I want to insert into the second table.
My problem is I have many records coming from selects I want to insert in both tables, I've not been able to think of a set based way to do these inserts.
My current solution is to use a cursor, insert in the first table, get key using scope_identity, insert into second table, repeat.
Am I missing a non-cursor solution?
Yes, Look up the output clause in Books online.
I had this problem just this week: someone had introduced a table with a meaningless surrogate key into the schema where naturally keys are used. No doubt I'll fix this soon :) until then, I'm working around it by creating a table of data to INSERT from: this could be a permanent or temporary base table or a derived table (see below), which should suit your desire for a set-based solution anyhow. Use a join between this table and the table with the IDENTITY column on the natural key to find out the auto-generated values. Here's a brief example:
CREATE TABLE Test1
(
surrogate_key INTEGER IDENTITY NOT NULL UNIQUE,
natural_key CHAR(10) NOT NULL CHECK (natural_key NOT LIKE '%[^0-9]%') UNIQUE
);
CREATE TABLE Test2
(
surrogate_key INTEGER NOT NULL UNIQUE
REFERENCES Test1 (surrogate_key),
data_col INTEGER NOT NULL
);
INSERT INTO Test1 (natural_key)
SELECT DT1.natural_key
FROM (
SELECT '0000000001', 22
UNION ALL
SELECT '0000000002', 55
UNION ALL
SELECT '0000000003', 99
) AS DT1 (natural_key, data_col);
INSERT INTO Test2 (surrogate_key, data_col)
SELECT T1.surrogate_key, DT1.natural_key
FROM (
SELECT '0000000001', 22
UNION ALL
SELECT '0000000002', 55
UNION ALL
SELECT '0000000003', 99
) AS DT1 (natural_key, data_col)
INNER JOIN Test1 AS T1
ON T1.natural_key = DT1.natural_key;