Merge statement that allows insertion of duplicates - sql

I have two tables,
Table 1
Id | medicineName
-------------------------
1 | benalgin
2 | xanax
3 | xanax
-------------------------
And I have this second table, where I need to insert the ID from the above table into the second table (which has null values in the medicineId column), and I need to use MERGE statement that will allow me to insert duplicates.
Table 2
medicineId | medicine
-------------------------
null | xanax
null | xanax
null | operil
-------------------------
I have tried this, but since I need to have duplicate records with different ID, I get the error:
cannot insert or update duplicate rows
MERGE table2 b
USING table1 a
ON (a.MedicineName = b.Medicine and a.Id is null)
when matched
then update set
a.Id = b.MedicineId;

I think that you do need two queries for this.
First update the existing records in table2 with one of the ids coming from table1:
update table2
set medicineId = (
select min(id) from table1 t1 where t1.medicineName = table2.medicine
)
Then insert the missing records:
insert into table2 (medicineId, medicine)
select id, medicineName
from table1 t1
where not exists (
select 1 from table2 t2 where t2.medicineId = t1.id and t2.medicine = t1.medicineName
)
Demo on DB Fiddle
Table content after update:
MEDICINEID | MEDICINE
:--------- | :-------
2 | xanax
2 | xanax
null | operil
Table content after insert:
MEDICINEID | MEDICINE
:--------- | :-------
2 | xanax
2 | xanax
null | operil
3 | xanax
1 | benalgin

Related

Repeat same data based on for each value in another table's column

I have two data tables:
+---------+--------+ +---------+
|Account | Value | | Version |
+---------+--------+ +---------+
| 1 | 10 | | a |
+---------+--------+ +---------+
| 2 | 20 | | b |
+---------+--------+ +---------+
Basically, what I want to do is to add column "version" to the first table and repeat data for each version, e.g:
+---------+--------+---------+
|Account | Value | Version |
+---------+--------+---------+
| 1 | 10 | a |
+---------+--------+---------+
| 2 | 20 | a |
+---------+--------+---------+
| 1 | 10 | b |
+---------+--------+---------+
| 2 | 20 | b |
+---------+--------+---------+
Unfortunately, I can't hard-write the version names since they change very frequently, but data itself is static. Any idea how to do it with SQL?
This sounds like a cross join:
select t1.*, t2.*
from table1 t1 cross join
table2 t2;
This produces a Cartesian product of the two tables -- which is exactly what your question describes.
Note that if either table is empty, this will return no rows.
You can do this in two ways:
First: by executing the below script you will have a table that you desired.
create table yourTableName as
(select t1.*, t2.*
from table1 t1 cross join
table2 t2
)
Second:
Add column version to table1 as nullable
alter table table1 add column version varchar(20)
insert combination data to table1
insert into table1 (Account, Value, Version)
(select t1.*, t2.*
from table1 t1 cross join
table2 t2
)
delete rows that version column is null
delete from table table1 where version is null

Combining multiple tables with same ID

I am trying to combine several tables. The goal is to have them all on one table in the end, but sorted by ID. So if I have a matching ID between some of the tables, it unites into one row based on the ID.
There are more than two tables (I currently have three: table1, table2, table3 but I plan to add more in the future)
Some of the tables don't have the same columns or number of columns.
Some of the tables don't have the same name for the ID column, table1 has "ID" and table2 has it named "identity" and so on...
I try not to include each of all the available columns from every table in the code, because there's a good amount of columns in each of the available tables and I assume adding and naming each one of them in the query would be tiring. I do however know the column name of the ID in each of the tables.
So the column names for the ID are: "ID(table1), Identity(table2), CatalogNum(table3)"
Here's an example,
table1:
**ID** | Name | Price | Date | ....
000212 Rod 200 NULL etc
......
table2:
Descr | **Identitiy** | amount | ...
Silver rod 000212 3 NULL
......
table3:
Type | Price | Condition | **CatalogNum** | .....
Metal NULL 8 000212 etc
Wood 300 1 000313 etc
.....
So end result should look like:
**ID** | Name | Price | Date | Descr | amount | Type | Condition | .... | ... | .....
000212 Rod 200 NULL Silver rod 3 Metal 8 etc NULL etc
000313 NULL 300 NULL NULL NULL Wood 1 NULL NULL etc
is this what you want:
Select b.*, c.*, d.* From
(select ID from table1 union select Identitiy from table2 union select ID from table3)a
left join table1 b on a.ID = b.ID
left join table2 c on a.ID = c.Identitiy
left join table3 d on a.ID = d.ID
Since there's no single source for all of the ID values that could occur in the various tables, you'll have to build one, and then use that to join to all of the other tables to get the columns you're interested in.
For the purposes here, I pulled back all of the columns in all of the tables, though.
WITH IdList AS (
SELECT
ID AS MasterId
FROM table1
UNION
SELECT
Identitiy
FROM table2
UNION
SELECT
CatalogNum
FROM table3
)
SELECT
i.MasterID,
t1.*,
t2.*,
t3.*
FROM IdList as i
LEFT JOIN table1 as t1 ON t1.ID = i.MasterID
LEFT JOIN table2 as t2 ON t2.Identitiy = i.MasterID
LEFT JOIN table3 as t3 ON t3.CatalogNum = i.MasterID;
Result:
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
| MasterID | ID | Name | Price | Date | Descr | Identitiy | amount | Type | Price | Condition | CatalogNum |
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
| 000212 | 000212 | Rod | 200 | (null) | Silver rod | 000212 | 3 | Metal | (null) | 8 | 000212 |
| 000313 | (null) | (null) | (null) | (null) | (null) | (null) | (null) | Wood | 300 | 1 | 000313 |
+----------+--------+--------+--------+--------+------------+-----------+--------+-------+--------+-----------+------------+
SQL Fiddle demo
EDIT: Your question notes that you want the data in one table, ", but sorted by ID." SQL tables don't work that way. They are, by definition, unordered sets. You impose order on them by using an ORDER BY clause in your SELECT queries. So there is no effort in my query above to create any kind of "order" at all.

Update and Replace Values in one Table Column with Values from another Table Column

I have 2 tables:
id | bsi | cell
1 | 45 | NULL
2 | 23 | 600-1167
3 | 47 |
4 | 89 | 501- -
5 | 98 | 603-5670
I would like to replace cell values with data from another colum in another table matching both tables by bsi
Here is my 2nd table:
id | bsi | contact
1 | 45 | 610-5896
2 | 23 | 605-4567
3 | 47 | NULL
4 | 89 | 689-9089
5 | 98 | NULL
I would like each value in the first table replaced with the new value in 2nd table also the value where both tables match in bsi code ie to replace the NULL and '501- -' with the new value once there is one in the 2nd table.
So result should be an updated table as follows:
id | bsi | cell
1 | 45 | 610-5896
2 | 23 | 605-4567
3 | 47 | NULL
4 | 89 | 689-9089
5 | 98 | 603-5670
I have tried this query but it only replaces the new values and seems to write null values for items that are in table1 and not table2. I want to keep the table1 values that are in table 1 but not table 2.
UPDATE Table1
SET Table1.cell = Table2.Contact
FROM Table1 INNER JOIN Table1 ON Table1.bsi = Table2.bsi
Your join seems to be a little off... you aren't joining the second table
UPDATE t1
SET t1.cell = t2.Contact
FROM Table1 t1
INNER JOIN Table2 t2 ON --changed to table2
t1.bsi = t2.bsi
--where <some condition>
Also, it can be faster to just update all rows than to be selective using a where clause. See Aaron Bertrand's tests on this. I did it this way because despite you stating that I want to keep the table1 values that are in table 1 but not table 2, this wasn't reflected in your expected output. If you really do want to conditionally update them, then you need to add the where clause.
SEE DEMO HERE
create table table1 (id int, bsi int, cell varchar(16))
create table table2 (id int, bsi int, contact varchar(16))
insert into table1 values
(1,45,NULL),
(2,23,'600-1167'),
(3,47,''),
(4,89,'501- -')
insert into table2 values
(1,45,'610-5896'),
(2,23,'605-4567'),
(3,47,NULL),
(4,89,'689-9089')
UPDATE t1
SET t1.cell = t2.Contact
FROM Table1 t1
INNER JOIN Table2 t2 ON --changed to table2
t1.bsi = t2.bsi
--where <some condition>
select * from table1
RETURNS
+----+-----+----------+
| id | bsi | cell |
+----+-----+----------+
| 1 | 45 | 610-5896 |
| 2 | 23 | 605-4567 |
| 3 | 47 | |
| 4 | 89 | 689-908 |
+----+-----+----------+
It looks like your query was joining back on itself. Change the table you are joining on to be Table2 instead.
This will update only rows in Table1 that match up with rows in Table2 by the bsi value, setting the cell value to Contact
UPDATE Table1
SET Table1.cell = Table2.Contact
FROM Table1
INNER JOIN Table2
ON Table1.bsi = Table2.bsi

Join multiple tables using SQL & T-SQL

Unfortunately, I cannot be sure that the name of my question is correct here.
Example of initial data:
Table 1 Table 2 Table 3
| ID | Name | | ID | Info1 | | ID | Info2 |
|----|-------| |----|-------| |----|-------|
| 1 | Name1 | | 1 | text1 | | 1 | text1 |
| 2 | Name2 | | 1 | text1 | | 1 | text1 |
| 3 | Name3 | | 2 | text2 | | 1 | text1 |
| 2 | text2 | | 2 | text2 |
| 3 | text3 |
In my initial data I have relationship between 3 tables by field ID.
I need to join table2 and table3 to the first table, but if I do sequential join, like left join table2 and left join table3 by ID I will get additional records on second join, because there will be several records with one ID after first join.
I need to get records of table2 and table3 like a list in each column for ID of first table.
Here an example of expected result:
Table 3
| ID | Name |Info1(Table2)|Info2(Table3)|
|-------|-----------|-------------|-------------|
| 1 | Name1 | text1 | text1 |
| 1 | Name1 | text1 | text1 |
| 1 | Name1 | null | text1 |
| 2 | Name2 | text2 | text2 |
| 2 | Name2 | text2 | null |
| 3 | Name3 | null | text3 |
This is the method I would use, however, the table design you have could probably be improved on; why are Table2 and Table3 separate in the first place?
USE Sandbox;
GO
CREATE TABLE dbo.Table1 (ID int, [Name] varchar(5))
INSERT INTO dbo.Table1 (ID,
[Name])
VALUES(1,'Name1'),
(2,'Name1'),
(3,'Name3');
CREATE TABLE dbo.Table2 (Id int,Info1 varchar(5));
CREATE TABLE dbo.Table3 (Id int,Info2 varchar(5));
INSERT INTO dbo.Table2 (Id,
Info1)
VALUES(1,'text1'),
(1,'text1'),
(2,'text2'),
(2,'text2');
INSERT INTO dbo.Table3 (Id,
Info2)
VALUES(1,'text1'),
(1,'text1'),
(1,'text1'),
(2,'text2'),
(3,'text3');
WITH T2 AS(
SELECT ID,
Info1,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT NULL)) AS RN --SELECT NULL as you have no other columns to actually create an order
FROM Table2),
T3 AS(
SELECT ID,
Info2,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY (SELECT NULL)) AS RN
FROM Table3),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I --Assuming you have 10 or less matching items
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N))
SELECT T1.ID,
T1.[Name],
T2.info1,
T3.info2
FROM Table1 T1
CROSS JOIN Tally T
LEFT JOIN T2 ON T1.ID = T2.ID AND T.I = T2.RN
LEFT JOIN T3 ON T1.ID = T3.ID AND T.I = T3.RN
WHERE T2.ID IS NOT NULL OR T3.ID IS NOT NULL
ORDER BY T1.ID, T.I;
GO
DROP TABLE dbo.Table1;
DROP TABLE dbo.Table2;
DROP TABLE dbo.Table3;
If you have more than 10 rows, then you could build a "proper" tally table on the fly, or create a physical one. One on the fly is probably going to be a better idea though, as I doubt you're going to have 100's of matching rows.

SQL get data that doesn't exist on another table

I'm trying to get a query that get me a data that exist in table1 but not on table2, but has the same id with data table2.
In the following example, I'm trying to get 'SecID-by_Bank' 12456 which shares the same ISIN as another 2 items in table2.
I've tried the following query, but it returned me every data that's not on table2, not just the one that shares the same ISIN.
Query:
SELECT tb1_isin, tb1_SecID_by_Bank
FROM table1
WHERE not EXISTS (
SELECT top 1 null
FROM table2
WHERE table1.tb1_ISIN = table2.tb2_isin
)
Table 1
--------------------------------------------
Row | SecID_by_Bank | Desc | ISIN
--------------------------------------------
1 | 421345 | BlaBla | US1354
--------------------------------------------
499 | 34345 | 2.US | XS1545
--------------------------------------------
500 | 45676 | 2/US | XS1545
--------------------------------------------
501 | 12456 | 2-US | XS1545
--------------------------------------------
Table 2
--------------------------------------------
Row | SecID_by_Bank | Desc | ISIN
--------------------------------------------
1 | 34345 | 2.US | XS1545
--------------------------------------------
2 | 45676 | 2/US | XS1545
Query result needed:
SecID_by_Bank | Desc | ISIN
-------------------------------------
| 12456 | 2-US | XS1545
-------------------------------------
What am I missing?
Thank you!
If you build query in Access try:
SELECT Table1.*
FROM Table1
WHERE (((Table1.[ISIN]) In (SELECT ISIN FROM Table2)) AND ((Table1.SecID_by_Bank) Not In (SELECT SecID_by_BANK FROM Table2)));
Or using 1 subquery:
SELECT Table1.*, Table2.ISIN
FROM Table2 RIGHT JOIN Table1 ON Table2.SecID_by_Bank = Table1.SecID_by_Bank
WHERE (((Table1.ISIN) In (SELECT ISIN FROM Table2)) AND ((Table2.ISIN) Is Null));
For query in SQLServer:
select distinct a.SecID_by_Bank, a.[desc], a.isin from #table1 a left join #table2 b
on a.SecID_by_Bank=b.SecID_by_Bank and a.isin=b.isin
join #table2 c on a.isin=c.isin
where b.isin is null