Insert lost data to the table - sql

I have two tables, which have two common column 'StationID'.
Create table t1(ID int, StationID bigint)
insert into t1 values
(0,1111),
(1,2222),
(2,34),
(3,456209),
(56,78979879),
(512,546)
go
Create table t2(StationID bigint, Descr varchar(50))
insert into t2 values
(-1,'test-1'),
(0,'test0'),
(1,'test1'),
(2,'test2'),
(5001,'dummy'),
(5002,'dummy'),
(6001,'dummy')
go
Now we notice that not every t1.StationID is in t2.StationID. Run the script can prove it.
select distinct StationID from t1 as A
where not exists
(select * from t2 as B where B.StationID =A.StationID)
The result is:
StationID
34
546
1111
2222
456209
78979879
Now I want to fill t2 with the lost StationID above, the column Descr can be any dummy data.
My real case has thousands records, how to use script to implement it?

insert into t2 (StationID, Descr)
select distinct StationID, 'dummy'
from t1 as A
where not exists
(select * from t2 as B where B.StationID =A.StationID)

INSERT INTO
t2
SELECT DISTINCT
stationid, 'dummy'
FROM
t1
WHERE
stationid NOT IN (SELECT stationid FROM t2)
(As an alternative to the others).

Related

Why does selecting all columns change the order

I have 2 tables. The order of selecting with a select * is different than the order of selecting without the wildcard.
This issue is happening on a production environment.
I have tried to replicate this issue but have not succeeded.
What could be causing this issue in the production tables?
DROP TABLE IF EXISTS #table1
DROP TABLE IF EXISTS #table2
CREATE TABLE #table1 (id int, code varchar(10), carriercode varchar(10), maxvalue numeric(14,3))
CREATE TABLE #table2 (id int, carriercode varchar(10))
-- notice the maximum value is always 2000.000
INSERT INTO #table1 (id,code,carriercode, maxvalue) SELECT 1,'a','carrier_a',2000.000
INSERT INTO #table1 (id,code,carriercode, maxvalue) SELECT 2,'a','carrier_b',2000.000
INSERT INTO #table1 (id,code,carriercode, maxvalue) SELECT 3,'c','carrier_c',2000.000
INSERT INTO #table2 (id,carriercode) SELECT 1,'carrier_a'
INSERT INTO #table2 (id,carriercode) SELECT 2,'carrier_b'
This is the select without the wildcard
SELECT t1.id,t1.code,t1.parentcode,t1.carriercode
FROM #table1 t1
LEFT JOIN #table2 t2 on t1.carriercode=t2.carriercode
WHERE (t1.parentcode = 'a')
AND (t1.maxvalue >= 830 OR t1.maxvalue is null)
ORDER BY t1.maxvalue DESC
And the result
id code parentcode carriercode
1 a1 a carrier_a
2 a2 a carrier_b
Here the select with the wildcard
SELECT t1.id,t1.code,t1.parentcode,t1.carriercode,*
FROM #table1 t1
LEFT JOIN #table2 t2 on t1.carriercode=t2.carriercode
WHERE (t1.parentcode = 'a')
AND (t1.maxvalue >= 830 OR t1.maxvalue is null)
ORDER BY t1.maxvalue DESC
And the second result
id code parentcode carriercode id code parentcode carriercode maxvalue dt id carriercode
1 a1 a carrier_a 1 a1 a carrier_a 2000.000 2022-09-30 22:49:52.787 1 carrier_a
2 a2 a carrier_b 2 a2 a carrier_b 2000.000 2022-09-30 22:49:52.787 2 carrier_b
Notice that the order of table 1 id column is the same for both select statements. On the production tables the 2 select statements are ordered differently.
What I have tried
Rounding issues: CAST numeric to int -> order is still the same for both selects
Changed the order of the initial inserts -> order is still equal for both selects
Because the order of rows that are tied based on your ORDER BY is undocumented and depends on the details of the execution plan.
To fix the order, ensure your ORDER BY includes enough columns to uniquely order the rows. EG
ORDER BY t1.maxvalue DESC, id

max date for multiple id using different tables

I have 3 tables (SQL Server 2008 R2):
Table 1
ID Date
123 20-08-2011
123 20-08-2011
234 30-09-2012
Table 2
ID Centre ChangeDate
123 987 16-08-11
123 568 28-05-10
234 456 14-09-12
Table 3
Centre Centre_Name
987 test1
568 test2
456 test3
I would like to make a query which joins all columns and only selects the Centre with the maximum ChangeDate. Thus, the following table should be returned:
ID Date Centre ChangeDate Centre_Name
123 20-08-11 987 16-08-11 test1
123 20-08-11 987 16-08-11 test1
234 30-09-12 456 14-09-12 test3
Thank you.
There should be multiple ways of achieving your results. One way is by using a row_number() partitioned by your [Id] column (or [Id] and [Centre] if you want the Id/Centre combinations with the highest [ChangeDate]). This will yield unique results, and wouldn't fit your desired result as described in your answer (my question would be: why would you want duplicated answers?). The other method is using a subquery to retrieve the maximum changedate from Table 2 per Id, and subsequently joining that result tot Table 2 for a second time.
declare #table1 table ([Id] INT, [Date] date)
declare #table2 table ([Id] INT, [Centre] int, [ChangeDate] date)
declare #table3 table ([Centre] int, [Centre_Name] varchar(25))
insert into #table1 values (123,'2011-08-20'),(123,'2011-08-20'),(234,'2012-09-30')
insert into #table2 values (123,987,'2011-08-16'),(123,568,'2010-05-28'),(234,456,'2012-09-14')
insert into #table3 values (987,'test1'),(568,'test2'),(456,'test3')
Method 1: using row_number()
select *
from (
select t1.[Id],t1.[Date],t2.[Centre],t2.[ChangeDate],t3.[Centre_Name]
, rn=row_number() over (partition by t2.[Id]/*, t2.[Centre]*/ order by t2.[ChangeDate] desc)
from #table1 t1
join #table2 t2 on t2.Id = t1.Id
join #table3 t3 on t3.Centre=t2.Centre
) x where x.rn=1
Method 2: using a subquery to retrieve the maximum [ChangeDate] per [Id]
select t1.[Id],t1.[Date],t2.[Centre],t2.[ChangeDate],t3.[Centre_Name]
from #table1 t1
join (select Id, maxChangeDate=max(ChangeDate) from #table2 group by Id ) t2_maxChangeDate on t1.[Id]=t2_maxChangeDate.[Id]
join #table2 t2 on t2.[Id]=t2_maxChangeDate.[Id] and t2.[ChangeDate]=t2_maxChangeDate.[maxChangeDate]
join #table3 t3 on t3.[Centre] = t2.[Centre]
I would use apply :
select t1.*, tt.*
from table1 t1 cross apply
( select top (1) t2.Centre, t2.ChangeDate, t3.Centre_Name
from table2 t2 inner join
table3 t3
on t3.Centre = t2.Centre
where t2.id = t1.id
order by t2.ChangeDate desc
) tt;

select table to select from, dependent on column-value of already given table

for my intention I have to select a table to select columns from dependent on the column-value of an already given table.
First I thought about a CASE construct, if this is possible with sqlite.
SELECT * FROM
CASE IF myTable.column1 = "value1" THEN (SELECT * FROM table1 WHERE ...)
ELSE IF myTable.column1 = "value2" THEN (SELECT * FROM table2 WHERE ...)
END;
I am new to SQL. What construct would be the most concise (not ugly) solution and if I cannot have it in sqlite, what RDBM would be the best fit?
Thanks
Here is a proposal for associating a value from one of two tables for each entry in mytable. I.e. this is making the assumption that mytable does not only contain a single entry for choosing the secondary table.
For details on what this means, see "MCVE" at the end of this answer.
If you want to switch between two secondary tables, based on a single entry in main table, see at the very end of this answer.
Details:
a hardcoded "value1"/"value2" as column1 added on the fly to the result from secondary tables
joining by the faked colummn1 and a secondary join-key, assumption here id
a union all to make a single table from both secondary tables (including the fake column1)
select *
from mytable
left join
(select 'value1' as column1, * from table1
UNION ALL
select 'value2' as column1, * from table2)
using(id, column1);
Output (for the MCVE provided below, "a-f" from table1, "A-Z" from table2):
value1|1|a
value2|2|B
value1|3|c
value1|4|d
value2|5|E
value2|6|F
MCVE:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE mytable (column1 varchar(10), id int);
INSERT INTO mytable VALUES('value1',1);
INSERT INTO mytable VALUES('value2',2);
INSERT INTO mytable VALUES('value1',3);
INSERT INTO mytable VALUES('value1',4);
INSERT INTO mytable VALUES('value2',5);
INSERT INTO mytable VALUES('value2',6);
CREATE TABLE table2 (value varchar(2), id int);
INSERT INTO table2 VALUES('F',6);
INSERT INTO table2 VALUES('E',5);
INSERT INTO table2 VALUES('D',4);
INSERT INTO table2 VALUES('C',3);
INSERT INTO table2 VALUES('B',2);
INSERT INTO table2 VALUES('A',1);
CREATE TABLE table1 (value varchar(2), id int);
INSERT INTO table1 VALUES('a',1);
INSERT INTO table1 VALUES('b',2);
INSERT INTO table1 VALUES('c',3);
INSERT INTO table1 VALUES('d',4);
INSERT INTO table1 VALUES('e',5);
INSERT INTO table1 VALUES('f',6);
COMMIT;
For selecting between two tables based on a single entry in main table (in this case "mytable2":
select * from table1 where (select column1 from mytable2) = 'value1'
union all
select * from table2 where (select column1 from mytable2) = 'value2';
Output (with mytable2 only containing 'value1'):
a|1
b|2
c|3
d|4
e|5
f|6

SQL Server insert with row N referencing the identity of the N - 1 row. Possible?

I have a SQL Server 2008 DB with a table like this (Table1):
ID ParentID Name
-- -------- ---
11 NULL Foo
12 11 Bar
13 12 etc
ID is declared with IDENTITY.
I have the values Foo, Bar, etc as rows in another table (Table2) and I must insert them in Table1.
The inserted values must be in a parent child relation in Table1, with ParentID column from row N pointing to ID of row N-1.
Is it possible with one statement to insert the values with the relations between them?
-- Insert all names in first table
insert Table1
(Name)
select Name
from Table2
-- For each row in Table1,
-- Search for the matching row in Table2,
-- Then look up the "parent" row in Table2,
-- And back to Table1 for the "parent" id
update t1
set ParentID = t1_parent.ID
from Table1 t1
join Table2 t2
on t1.Name = t2.name
cross apply
(
select top 1 *
from Table2 t2_parent
where t2_parent.ID < t2.ID
order by
t2_parent.ID desc
) t2_parent
join Table1 t1_parent
on t1_parent.Name = t2_parent.Name
Since you asked if you could do this in one statement, here is an answer for that. I can't help but feel that if you had given more information I would be telling that whatever you're doing this for should be solved another way. I'm having a hard time coming up with a good reason to do this. Here is a way to do it regardless though:
I am assuming Table1 has Id, ParentId, and Name, and that Table2 has Id and Name (you said you got the names Foo, Bar, whatever from Table2). I'm also assuming there is some order you can impose.
CREATE TABLE #T
(
Id INT IDENTITY(1, 1)
, ParentId INT
, Name VARCHAR(100)
)
CREATE TABLE #T2
(
Id INT IDENTITY(1, 1)
, Name VARCHAR(100)
)
INSERT #T2
(
Name
)
VALUES ('Foo'), ('Bar')
INSERT #T
(
ParentId
, Name
)
SELECT
NULLIF(IDENT_CURRENT('#T')
+ ROW_NUMBER() OVER(ORDER BY T2.Name)
- 2, (SELECT ISNULL(MIN(Id), 1) - 1 FROM #T))
, T2.Name
FROM #T2 T2
SELECT * FROM #T
DROP TABLE #T
DROP TABLE #T2

How to create a view which merges two tables?

I have two tables which have the exact same structure. Both tables can store the same data with different primary keys (autoincremented integers). Therefore, there is a third table which lists which two primary keys list the same data. However, there also exist rows which don't exist in the other. Therefore, a simple join won't work since you will have two rows with the same primary key but different data. Therefore, is there a way of reassigning primary keys to unused values in the view?
Table1
ID name
1 Adam
2 Mark
3 David
4 Jeremy
Table2
ID name
1 Jessica
2 Jeremy
3 David
4 Mark
Table3
T1ID T2ID
2 4
3 3
4 2
I am looking for a result table like the following:
Result
ID name
1 Adam
2 Mark
3 David
4 Jeremy
5 Jessica
The real heart of the question is how i can assign the temporary fake id of 5 to Jessica and not just some random number. The rule I want for the ids is that if the row exists in the first table, then use its own id. Otherwise, use the next id that an insert statement would have generated (the column is on autoincrement).
Answer to edited question
select id, name from table1
union all
select X.offset + row_number() over (order by id), name
from (select MAX(id) offset from table1) X
cross join table2
where not exists (select * from table3 where t2id = table2.id)
The MAX(id) is used to "predict" the next identity that would occur if you merged the data from the 2nd table into the first. If Table3.T2ID exists at all, it means that it is already included in table1.
Using the test data below
create table table1 (id int identity, name varchar(10))
insert table1 select 'Adam' union all
select 'Mark' union all
select 'David' union all
select 'Jeremy'
create table table2 (id int identity, name varchar(10))
insert table2 select 'Jessica' union all
select 'Jeremy' union all
select 'David' union all
select 'Mark'
create table table3 (t1id int, t2id int)
insert table3 select 2,4 union all
select 3,3 union all
select 4,2
Answer to original question below
So the 3rd table is the one you want to build (a view instead of a table)?
select newid=row_number() over (order by pk_id), *
from
(
select a.*
from tblfirst a
UNION ALL
select b.*
from tblsecond b
) X
The data will contain a unique newid value for each record, whether from first or second table. Change pk_id to your primary key column name.
Assuming you have below data, as I understand reading your question:
Table: T1
ID name
--------
1 a
2 b
3 c
Table: T2
ID name
--------
2 b
3 c
4 d
Table: Rel
ID1 ID2
--------
2 2
3 3
T1 has some data which is not in T2 and vice versa.
Following query will give all data unioned
SELECT ROW_NUMBER() OVER (order by name) ID, Col
from
(
SELECT ISNULL(T1.name,'') name
FROM T1 t1 LEFT JOIN Rel TR ON TR.ID1 = T1.ID
union
SELECT ISNULL(T2.name,'') name
FROM T2 t2 LEFT JOIN Rel TR ON TR.ID2 = T2.ID
) T
If I understand you correct, following might work
Select everything from your first table
Select everything from your second table that is not linked to your third table
Combine the results
Test data
DECLARE #Table1 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table2 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table3 TABLE (T1ID INTEGER, T2ID INTEGER)
INSERT INTO #Table1 VALUES ('Adam')
INSERT INTO #Table1 VALUES ('Mark')
INSERT INTO #Table1 VALUES ('David')
INSERT INTO #Table1 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('Jessica')
INSERT INTO #Table2 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('David')
INSERT INTO #Table2 VALUES ('Mark')
INSERT INTO #Table3 VALUES (2, 4)
INSERT INTO #Table3 VALUES (3, 3)
INSERT INTO #Table3 VALUES (4, 2)
SQL Statement
SELECT ROW_NUMBER() OVER (ORDER BY ID), t1.Value
FROM #Table1 t1
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY ID) + offset, t2.Value
FROM #Table2 t2
LEFT OUTER JOIN #Table3 t3 ON t3.T2ID = t2.ID
CROSS APPLY (
SELECT Offset = COUNT(*)
FROM #Table1
) offset
WHERE t3.T2ID IS NULL