Distinct value in array - sql

Hello i have problem i have table
CREATE TABLE doctor(
idDoc SERIAL PRIMARY KEY,
meds TEXT[]
);
I want to store only unique values if my user enter same meds inside
Table before user insert
id
meds
1
{Nalfon,Ocufen,Actron}
After user insert (insert is Actron,Soma,Robaxin) i want update and have in table old values and new values ( Actron is same)
if I UPDATE table with new values I will get
UPDATE doctor SET meds='{Actron,Soma,Robaxin}') WHERE id=1;
id
meds
1
{Actron,Soma,Robaxin}
But i want
id
meds
1
{Nalfon,Ocufen,Actron,Soma,Robaxin}
I don't know how to check if new value is same like value in table and only insert/update table to have unique values.

Given your data structure, you can unnest the existing meds, add in the new ones, and re-aggregate as a unique array:
UPDATE doctor d
SET meds = (select array_agg(distinct med)
from (select med
from unnest('{Actron,Soma,Robaxin}'::text[]) u(med)
union all
select med
from unnest(d.meds) u(med)
) m
)
WHERE idDoc = 1;
Here is a db<>fiddle.
That said, you might consider a junction table with one row per doctor and medicine. That is the more traditional SQL representation for a many-to-many relationship.

Related

Create a record in table A and assign its id to table B

I have a set of companies and for each of them, I need to generate a UUID in another table.
companies table
detail_id (currently NULL for all companies)
details table
id
uuid
date
...
I'd like to update all companies with newly created detail like this:
UPDATE companies
SET details_id =
(
INSERT INTO details
(uuid, date)
VALUES (uuid_generate_v1(), now()::date)
RETURNING id
)
But that gives me a syntax error since I can't use INSERT INTO inside UPDATE.
What is a proper way to create a row in the details table and immediately set the newly created id in the companies table?
(I am using Postgres)
You can use a data-modifying CTE:
with new_rows as (
INSERT INTO details ("uuid", "date")
VALUES (uuid_generate_v1(), current_date)
RETURNING id
)
update companies
set details_id = new_rows.id
from new_rows

sql conversion script

I have a 2 databases that I want to merge with some similiar tables. The source tables have id as bigint and my destination table has int as ID. There aren't that many records in my source table (< 20k) so I want to assign new ids to all records so the ids can fit in an int. How can I do this with sql?
First Option
You can Use Sequence object as follow:
First Create a Sequence object and assign it's Start With value to max Id value in destination table plus 1. For example if max Id in destination table is 100, you need to assign 101 as Start With. You can also obtain the max Id value from destination table using a Max(Id) aggregate function and store it in a variable:
CREATE SEQUENCE SeqId
START WITH [Max value of Id in destination table]
INCREMENT BY 1 ;
GO
Then insert to destination table using following query:
Insert Into tblXXX (Id, ...) Values (NEXT VALUE FOR SeqId, ...)
Read more about Sequence Object
Second Option
You can make the destination table's Id column as Identity column with seed equal to destination table's Id column max value and Increment equal to 1.
Here is detailed example also Here
You did not provide much details so I can only provide a general guideline:
Note: Example assumes that you want to merge tables A and B into C and you want to generate new IDs. I also assume that these IDs are not referenced by other tables (foreign keys).
First you get record counts from tables A and B:
DECLARE #countA INT
DECLARE #countB INT
SET #countA = ( SELECT COUNT(*) FROM A )
SET #countB = ( SELECT COUNT(*) FROM B )
Next you use a window function to generate new IDs and insert records into table C.
INSERT INTO C
SELECT #countA + ROW_NUMBER() OVER( ORDER BY ID ) AS ID, ....
FROM A
INSERT INTO C
SELECT #countA + #countB + ROW_NUMBER() OVER( ORDER BY ID ) AS ID, ....
FROM B

Using output to capture auto increment identity, plus past identity mapping table

I am trying to make exact copies of data in SQL, with new clientIDs, but keep the existing data in the old client as well. I will be inserting the data into a table with an auto incrementing integer primary key ID. I need to retain the ID's of the Old records and the new records together so I can continue using this mapping as I copy the different table data so I can maintain relationships.
At this point I have the following:
INSERT INTO [dbo].[Driver]
OUTPUT inserted.ID
inserted.Name
inserted.ClientID
SELECT Name,
1234 AS clientID
FROM dbo.Driver
I am wondering if there is a way to also select the old ID of the driver in the Output so I can then insert all of this into a holding table using the OUTPUT. So I need to end up with the following after I perform the insert into the dbo.Driver table so I can also insert these values into a temp table:
NewID
OldID
Name
ClientID
At this point I don't know of a way to pull the Original ID from the original record.
I ended up using MERGE INTO to keep track of the old ID as per the following SO post:
How to use OUTPUT to capture new and old ID?
you can try...
INSERT INTO dbo.Driver (oldID, Name, clientID)
SELECT
B.ID,
A.Name,
1234 AS clientID
FROM dbo.Driver A
LEFT JOIN dbo.Driver B ON A.Name = B.Name AND A.clientID = b.clientID
or maybe just
INSERT INTO dbo.Driver (oldID, Name, clientID)
SELECT
ID,
Name,
1234 AS clientID
FROM dbo.Drive

Copy selections from two related tables

I have two tables in a database. In the first table (tab1) I have a list of items. In the second table I have a many to many relationship between these items.
CREATE TABLE tab1(id INTEGER PRIMARY KEY ASC,set INTEGER, name TEXT);
CREATE TABLE tab2(id INTEGER PRIMARY KEY ASC,id1 INTEGER,id2 INTEGER,relationship TEXT);
The items in the first table are comprised of sets that all have the same value for the set field. I want to duplicate any given set with a new set id, such that the new set contains the same elements and relationships of the original set. If all the items in the set have sequential ids, I can do it as follows. First, find the highest id in the set (in this case, set 3):
SELECT id FROM tab1 WHERE set=3 ORDER BY id DESC LIMIT 1
I assign this to a variable $oldid. Next, I duplicate the items in tab1 matching the specified set, giving them a new set (in this case 37)
INSERT INTO tab1 (set,name) SELECT 37, name FROM tab1 WHERE set=3 ORDER BY id ASC
I then get the id of the last row inserted, and assign it to the variable $newid:
SELECT last_insert_rowid()
I then assign $diff = $newid-$oldid. Since the original set has sequential ids, I can simply select the original relationships for set=3, then add the difference:
INSERT INTO tab2 (id2,id2,relationship) SELECT id1+$diff,id2+$diff,type FROM tab WHERE id1 IN (SELECT id FROM tab WHERE set=3)
But this does not work if the set is not consisting of sequential ids in tab1. I could do a complete query of the original ids, then create a 1:1 mapping to the newly inserted ids for set 37, and then add the difference between each row, and then insert the newly computed rows in the table. But this requires loading all the selections to the client and doing all the work on the client. Is there some way to create a query that does it on the server in the general case?
Assuming that (set, name) is a candidate key for tab1, you can use these columns to look up the corresponding values:
INSERT INTO tab2(id1, id2, relationship)
SELECT (SELECT id
FROM tab1
WHERE "set" = 37
AND name = (SELECT name
FROM tab1
WHERE id = tab2.id1)),
(SELECT id
FROM tab1
WHERE "set" = 37
AND name = (SELECT name
FROM tab1
WHERE id = tab2.id2)),
relationship
FROM tab2
WHERE id1 IN (SELECT id
FROM tab1
WHERE "set" = 3)
OR id2 IN (SELECT id
FROM tab1
WHERE "set" = 3)

Insert data from one table to other using select statement and avoid duplicate data

Database: Oracle
I want to insert data from table 1 to table 2 but the catch is, primary key of table 2 is the combination of first 4 letters and last 4 numbers of the primary key of table 1.
For example:
Table 1 - primary key : abcd12349887/abcd22339887/abcder019987
In this case even if the primary key of table 1 is different, but when I extract the 1st 4 and last 4 chars, the output will be same abcd9887
So, when I use select to insert data, I get error of duplicate PK in table 2.
What I want is if the data of the PK is already present then don't add that record.
Here's my complete stored procedure:
INSERT INTO CPIPRODUCTFAMILIE
(productfamilieid, rapport, mesh, mesh_uitbreiding, productlabelid)
(SELECT DISTINCT (CONCAT(SUBSTR(p.productnummer,1,4),SUBSTR(p.productnummer,8,4)))
productnummer,
ps.rapport, ps.mesh, ps.mesh_uitbreiding, ps.productlabelid
FROM productspecificatie ps, productgroep pg,
product p left join cpiproductfamilie cpf
on (CONCAT(SUBSTR(p.productnummer,1,4),SUBSTR(p.productnummer,8,4))) = cpf.productfamilieid
WHERE p.productnummer = ps.productnummer
AND p.productgroepid = pg.productgroepid
AND cpf.productfamilieid IS NULL
AND pg.productietype = 'P'
**AND p.ROWID IN (SELECT MAX(ROWID) FROM product
GROUP BY (CONCAT(SUBSTR(productnummer,1,4),SUBSTR(productnummer,8,4))))**
AND (CONCAT(SUBSTR(p.productnummer,1,2),SUBSTR(p.productnummer,8,4))) not in
(select productfamilieid from cpiproductfamilie));
The highlighted section seems to be wrong, and because of this the data is not picking up.
Please help
Try using this.
p.productnummer IN (SELECT MAX(productnummer) FROM product
GROUP BY (CONCAT(SUBSTR(productnummer,1,4),SUBSTR(productnummer,8,4))))