sql server insert data from table1 to table2 where table1=table3 data - sql

I am trying to insert into Table A, unique data from Table B that matches data in TAble C but I am keep getting the violation of primary key error and not sure what I am doing wrong
Table A - bookfeed
Table B - bookF
Table C - bookStats
INSERT INTO bookFeed
(entryId,feed,entryContent,pubDate,authorName,authorId,age,
sex,locale,pic,fanPage, faceTitle,feedtype,searchterm,clientId,dateadded)
SELECT DISTINCT b.entryId,b.feed,b.entryContent,b.pubDate,b.authorName,
b.authorId,b.age,b.sex,b.locale,b.pic,b.fanPage,b.faceTitle,b.feedtype,
b.searchterm, b.clientId,b.dateadded
FROM bookF as b
INNER JOIN bookStats as a on a.feed = b.feed
WHERE NOT EXISTS (SELECT *
FROM bookFeed as c
WHERE c.entryId = b.entryId)
Table A bookFeed has a primary key on entryId

It looks like in table bookF, there are duplicate records per entryId
If you only want one entryId (limited by PK on bookFeed), you can use this. Adjust the order by in the ROW_NUMBER to suit
insert into bookFeed (
entryId,feed,entryContent,pubDate,authorName,authorId,age,
sex,locale,pic,fanPage,faceTitle,feedtype,searchterm,clientId,dateadded)
select
entryId,feed,entryContent,pubDate,authorName,authorId,age,
sex,locale,pic,fanPage,faceTitle,feedtype,searchterm, clientId,dateadded
from
(
select rn=Row_number() over (partition by b.entryId order by b.entryId),
b.entryId,b.feed,b.entryContent,b.pubDate,b.authorName,b.authorId,b.age,
b.sex,b.locale,b.pic,b.fanPage,b.faceTitle,b.feedtype,b.searchterm, b.clientId,b.dateadded
from bookF as b
inner join bookStats as a on a.feed = b.feed
left join bookFeed as c on c.entryId=b.entryId
where c.entryId is null
) X
where rn=1

UPDATE : Try this for you query and see if it works,look at the data and see if there are duplicates meaning all the entries should have an entry id different than what is currently there -
SELECT b.entryId,b.feed,b.entryContent,b.pubDate,b.authorName,
b.authorId,b.age,b.sex,b.locale,b.pic,b.fanPage,b.faceTitle,b.feedtype,
b.searchterm, b.clientId,b.dateadded
FROM bookF as b
INNER JOIN bookStats as a on a.feed = b.feed
WHERE b.entryId IN (SELECT distinct entryid
FROM bookFeed)
I think you are trying to insert an entry id which is an primary key(check if the value trying to insert is not an duplicate,null or violates any other of primary key constraint)...so either dont try to insert it if it gets populated automatically or in case you are looking to insert it then turn on identity insert on..and try again...
But ideally your id should be calculated (auto increment or something) and never be inserted directly.

Related

Insert results from select query, which is already changed

I want to run this query:
INSERT INTO contacts_fields (
contact_id, field_name, numeric_value
)
select distinct
c.id,
'storeId',
1
from
contacts c
inner join contacts_devices cd on cd.contact_id = c.id
and c.id NOT IN (
SELECT
contact_id
FROM
contacts_fields
)
group by
c.id
But I am getting an error:
SQL Error [23503]: ERROR: insert or update on table "contact_fields" violates foreign key constraint "contacts_fields_fkey"
Detail: Key (contact_id)=(2425542) is not present in table "contacts".
This is propably because contacts table is changing all the time, any maybe I can't insert value with id = 2425542, becasuse it was deleted between select and insert query. What can I do with this?

PostgreSQL | Need values from right table where is no match in m:n index

I have a three tables issue with PostgreSQL
table_left, table_index, table_right
table_index is m:n ...
I want to get all values from right table matching (m:n) and not-matching (NULL) values based on the values of left table.
SELECT field_left, field_index1, field_index2, field_right
FROM table_left
LEFT JOIN table_index ON left_id = index_left
LEFT JOIN table_right ON index_right = right_id
Using this query I get all values from left to right, but I'm not getting values from table_right were are not based in m:n table_index
If I do something like this ...
SELECT field_left, field_index1, field_index2, field_right
FROM table_left
LEFT JOIN table_index ON left_id = index_left
LEFT JOIN table_right ON index_right = right_id OR right_id NOT IN (1,2,3)
... I will get some strange results ...
field_index1, field_index2 using values from m:n but should be NULL because there is no dependency.
Any suggestions?
EDIT:
Have added some data ... Thx to #jarlh
DROP TABLE IF EXISTS "table_index";
CREATE TABLE "public"."table_index" (
"index_left" integer NOT NULL,
"index_right" integer NOT NULL,
"index_data1" character varying NOT NULL,
"index_data2" character varying NOT NULL,
CONSTRAINT "table_index_index_left_index_right" PRIMARY KEY ("index_left", "index_right"),
CONSTRAINT "table_index_index_left_fkey" FOREIGN KEY (index_left) REFERENCES table_left(left_id) NOT DEFERRABLE,
CONSTRAINT "table_index_index_right_fkey" FOREIGN KEY (index_right) REFERENCES table_right(right_id) NOT DEFERRABLE
) WITH (oids = false);
INSERT INTO "table_index" ("index_left", "index_right", "index_data1", "index_data2") VALUES
(1, 1, 'index-Left-A', 'index-Right-A'),
(1, 2, 'index-Left-A', 'index-Right-B'),
(1, 3, 'index-Left-A', 'index-Right-C'),
(2, 1, 'index-Left-B', 'index-Right-A');
DROP TABLE IF EXISTS "table_left";
DROP SEQUENCE IF EXISTS table_left_left_id_seq;
CREATE SEQUENCE table_left_left_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1;
CREATE TABLE "public"."table_left" (
"left_id" integer DEFAULT nextval('table_left_left_id_seq') NOT NULL,
"left_data" character varying NOT NULL,
CONSTRAINT "table_left_left_id" PRIMARY KEY ("left_id")
) WITH (oids = false);
INSERT INTO "table_left" ("left_id", "left_data") VALUES
(1, 'Left-A'),
(2, 'Left-B'),
(3, 'Left-C');
DROP TABLE IF EXISTS "table_right";
DROP SEQUENCE IF EXISTS table_right_right_id_seq;
CREATE SEQUENCE table_right_right_id_seq INCREMENT 1 MINVALUE 1 MAXVALUE 2147483647 START 1 CACHE 1;
CREATE TABLE "public"."table_right" (
"right_id" integer DEFAULT nextval('table_right_right_id_seq') NOT NULL,
"right_data" character varying NOT NULL,
CONSTRAINT "table_right_right_id" PRIMARY KEY ("right_id")
) WITH (oids = false);
INSERT INTO "table_right" ("right_id", "right_data") VALUES
(1, 'Right-A'),
(2, 'Right-B'),
(3, 'Right-C');
Using this query ....
SELECT left_id, left_data, index_left, index_right, index_data1, index_data2, right_id, right_data
FROM table_left
LEFT JOIN table_index ON left_id = index_left
LEFT JOIN table_right ON index_right = right_id
... I get some NULL values as expected...
Using the original database I'm not getting these kind of values. Have seen there is an id col within the index table. Primary isn't set to both id values from left/right like my test. Have changed this in my local db with the same result as my test before. I'm getting these NULL values as expected.
I want to get all values from right table matching (m:n) and not-matching (NULL) values based on the values of left table.
If you want all values from the right table, then left join is the right way to go. However the right table should be the first table in the from clause:
SELECT field_left, field_index1, field_index2, field_right
FROM table_right r LEFT JOIN
table_index i
ON i.index_right = r.right_id LEFT JOIN
table_left l
ON l.left_id = i.index_left;
Notes:
There is a bit of cognitive dissonance (in English) because the roles of left/right are reversed.
I recommend that you use table aliases for your actual tables.
I strongly, strongly recommend that you qualify all column references so it is clear what tables they come from.
You could also use RIGHT JOIN. However, I also recommend using LEFT JOIN for this type of logic. It is easier to follow query logic that says: "Keep all rows in the table you just read" rather than "Keep all rows in some table that you will see much further down in the FROM clause."
EDIT:
Based on your comments, I suspect you want a Cartesian product of all left and right values along with a flag that indicates if it is in the junction table. Something like this:
SELECT field_left, field_index1, field_index2, field_right
FROM table_right r CROSS JOIN
table_left l LEFT JOIN
table_index i
ON i.index_right = r.right_id AND
i.index_left = l.left_id;

SQL join based on select as column name

So in one table I can use a replace and charindex to extract a specific ID that relates to a PK in another table, I want to then join the data from the other table based on the trimmed value, how can I do this?
select top 100 *, Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID, PrmRoutingTask.*
from SytLog
inner join PrmRoutingTask on RtaId = TaskID
where LogTableName like '%Routing%' and LogValue like '%RtaAniId=397%'
order by 5 desc;
The problem I get is that the temp column name I create (TaskID) is not working in the inner join where in fact the results of TaskID have the reference to the RtaId in the RoutingTask table.
Assuming LogValue belongs to the first table you can use the column named TaskID if you produce a subquery as a table expression of the main query.
For example you can produce the column in the table expression a by doing:
select top 100
a.*,
PrmRoutingTask.*
from (
select *,
Replace(Left(LogValue,Charindex(';', LogValue) - 1) ,'RtaId=', '') as TaskID
from SytLog
) a
inner join PrmRoutingTask on PrmRoutingTask.RtaId = a.TaskID
where LogTableName like '%Routing%'
and LogValue like '%RtaAniId=397%'
order by 5 desc

How to differentiate between “no child rows exist” and “no parent row exists” in one SELECT query?

Say I have a table C that references rows from tables A and B:
id, a_id, b_id, ...
and a simple query:
SELECT * FROM C WHERE a_id=X AND b_id=Y
I would like to differentiate between the following cases:
No row exists in A where id = X
No row exists in B where id = Y
Both such rows in A and B exist, but no rows in C exist where a_id = X and b_id = Y
The above query will return empty result in all those cases.
In case of one parent table I could do a LEFT JOIN like:
SELECT * FROM A LEFT JOIN C ON a.id = c.a_id WHERE c.a_id = X
and then check if the result is empty (no row in A exists), has one row with NULL c.id (row in A exists, but no rows in C exist) or 1+ rows with non-NULL c.id (row in A exists and at least one row in C exists). A bit messy but it works, but I was wondering if there is a better way of doing this, especially if there is more than one parent table?
For example:
C is "things owned by people", A is "people", B is "types of things". When someone asks "give me a list of games owned by Bill", and there are no such records in C, I would like to return an empty list only if both "Bill" and "games" exist in their corresponding tables, but an error code if either of them doesn't.
So if there are no records matching "Bill" and "games" in table C, I would like to say "I don't know who Bill is" instead of "Bill has no games" if I don't have a record about Bill in table A.
create table a(a_id integer not null primary key);
create table b(b_id integer not null primary key);
create table c(a_id integer not null references a(a_id)
, b_id integer not null references b(b_id)
, primary key (a_id,b_id)
);
insert into a(a_id) values(0),(2),(4),(6);
insert into b(b_id) values(0),(3),(6);
insert into c(a_id,b_id) values(6,6);
PREPARE omg(integer,integer) AS
SELECT EXISTS(SELECT * FROM a where a.a_id = $1) AS a_exists
, EXISTS(SELECT * FROM b where b.b_id = $2) AS b_exists
, EXISTS(SELECT * FROM c where c.a_id = $1 and c.b_id = $2) AS c_exists
;
EXECUTE omg(1,1);
EXECUTE omg(2,1);
EXECUTE omg(1,3);
EXECUTE omg(6,6);
-- with optional payload:
PREPARE omg2(integer,integer) AS
SELECT val.a_id AS va_id
, val.b_id AS vb_id
, EXISTS(SELECT * FROM a WHERE a.a_id = $1) AS a_exists
, EXISTS(SELECT * FROM b WHERE b.b_id = $2) AS b_exists
, EXISTS(select * FROM c WHERE c.ca_id = val.a_id AND c.cb_id = val.b_id ) AS c_exists
, a.*
, b.*
, c.*
FROM (values ($1,$2)) val(a_id,b_id)
LEFT JOIN a ON a.a_id = val.a_id
LEFT JOIN b ON b.b_id = val.b_id
LEFT JOIN c ON c.ca_id = val.a_id AND c.cb_id = val.b_id
;
EXECUTE omg2(1,1);
EXECUTE omg2(2,1);
EXECUTE omg2(1,3);
EXECUTE omg2(6,6);
I think I managed to get a satisfactory solution using the following two features:
Subselect bound to a column, which allows me to check if a row exists and (importantly) get a NULL value otherwise (e.g. SELECT (SELECT id FROM a WHERE id = 1) as a_id))
Common Table Expressions
Initial data:
CREATE TABLE people
(
id integer not null primary key,
name text not null
);
CREATE TABLE thing_types
(
id integer not null primary key,
name text not null
);
CREATE TABLE things
(
id integer not null primary key,
person_id integer not null references people(id),
thing_type_id integer not null references thing_types(id),
name text not null
);
INSERT INTO people VALUES (1, 'Bill');
INSERT INTO thing_types VALUES (1, 'game');
INSERT INTO things VALUES (1, 1, 1, 'Duke Nukem');
INSERT INTO things VALUES (2, 1, 1, 'Warcraft 2');
And the query:
WITH v AS (
SELECT (SELECT id FROM people WHERE id=<person_id_param>) AS person_id,
(SELECT id FROM thing_types WHERE id=<thing_type_param>) AS thing_type_id
)
SELECT v.person_id, v.thing_type_id, things.name
FROM
v LEFT JOIN things
ON v.person_id = things.person_id AND v.thing_type_id = things.thing_type_id
This query will always return at least one row, and I just need to check which, if any, of the three columns of the first row are NULLs.
In case if both parent table ids are valid and there are some records, none of them will be NULL:
person_id thing_type_id name
-------------------------------------
1 1 Duke Nukem
1 1 Warcraft 2
If either person_id or thing_type_id are invalid, I get one row where name is NULL and either person_id or thing_type_id is NULL:
person_id thing_type_id name
-------------------------------------
NULL 1 NULL
If both person_id and thing_type_id are valid but there are no records in things, I get one row where both person_id and thing_type_id are not NULL, but the name is NULL:
person_id thing_type_id name
-------------------------------------
1 1 NULL
Since I have a NOT NULL constraint on things.name, I know that this case can only mean that there are no matching records in things. If NULLs were allowed in things.name, I could include things.id instead and check that for NULLness.
You have 3 cases, the third one is a bit more complex but can be achieved by using cross join between a and b, all three cases in a union could be like this
select a_id, b_id , 'case 1' from c
where not exists (select 1 from a where a.a_id=c.a_id)
union all
select a_id, b_id ,'case 2' from c
where not exists (select 1 from b where b.b_id=c.b_id)
union all
select a_id, b_id, 'case 3' from a cross join b
where exists (select 1 from c where c.a_id=a.a_id)
and exists (select 1 from c where c.b_id=b.b_id)
and not exists (select 1 from c where c.b_id=b.b_id and c.a_id=a.a_id)

How to massive update?

I have three tables:
group:
id - primary key
name - varchar
profile:
id - primary key
name - varchar
surname - varchar
[...etc...]
profile_group:
profile_id - integer, foreign key to table profile
group_id - integer, foreign key to table group
Profiles may be in many groups. I have group named "Users" with id=1 and I want to assign all users to this group but only if there was no such entry for the table profiles.
How to do it?
If I understood you correctly, you want to add entries like (profile_id, 1) into profile_group table for all profiles, that were not in this table before. If so, try this:
INSERT INTO profile_group(profile_id, group_id)
SELECT id, 1 FROM profile p
LEFT JOIN profile_group pg on (p.id=pg.profile_id)
WHERE pg.group_id IS NULL;
What you want to do is use a left join to the profile group table and then exclude any matching records (this is done in the where clause of the below SQL statement).
This is faster than using not in (select xxx) since the query profiler seems to handle it better (in my experience)
insert into profile_group (profile_id, group_id)
select p.id, 1
from profiles p
left join profile_group pg on p.id = pg.profile_id
and pg.group_id = 1
where pg.profile_id is null