How to Merge Tables and prevent IDs clashing - sql

I want to merge the IndirectFlights table to the PriceTable.
I do not have IDs entered in the SourceTable (IndirectFlights) and I haven't set a PK for it yet.
The ID column for the PriceTable is an Identity (1,1) column and is also the Primary Key.
Qs1 How do I enter IDs in Source column so that they dont clash with target table (PriceTable) IDs? I was thinking of using a sequence but It potentially could clash in future.
Qs2 Can I choose what columns to merge or must I merge all the columns from the Source table?
Target Table (PriceTable) Columns
IDAirport_ICAO_Code,Airline_ICAO_Code,Departure,Price,RouteStatus,DateRowModified
Source Table (IndirectFlights) Columns
IDAirport_ICAO_Code,Destination,Airline,Airline_ICAO_Code,RouteStatus,Connecting Airport
Edit: I have just run the following Union All statement as an alternative to using Merge.
Select ID,Airport_ICAO_Code,Airline_ICAO_Code,RouteStatus
From RoughworkPriceTable
Union All
Select ID,Airport_ICAO_Code,Airline_ICAO_Code,RouteStatus
From RoughworkIndirectFlights;
The code worked but i noticed that the ID column accepted the Null values from IndirectFlights.ID eventhough I have the ID columns set to Not Null.
Can anyone explain this.
Also can someone expalin how I could create a new permanent table from this Union All statement.

You can create a new table with something like
Select * into newTmpTable from (
Select ID,Airport_ICAO_Code,Airline_ICAO_Code,RouteStatus From RoughworkPriceTable
Union All
Select ID,Airport_ICAO_Code,Airline_ICAO_Code,RouteStatus From RoughworkIndirectFlights)
as mergedData;

Related

Matrix table index SQL Server 2008

I have a table with two columns built from another table of names, one identity and one a name like this:
ID---Name
1----Mike
2----Jeff
3----Robert
...down to however many
Could be 10 rows, could be 100. This will vary depending on input from other tables that are always changing but never be over 160 or so.
Now, pairings of names will have some meaning and thus a decimal data type score will be associated with said pairing (how at this point doesn’t matter, just need to build it for now...numbers just illustrative). I envision a matrix kind of like this:
ID------Name------Mike-------Jeff--------Robert-------- ...out to however many
1 -------Mike-------NULL------100.1------5.4-------- ...out to however many
2 -------Jeff---------100.1------NULL-----21.23--------- ...out to however many
3 ------Robert-------5.4--------21.23-----NULL---------...out to however many
…down to however many happen to be in the first table…
Maybe this isn’t quite the most optimal way to go (Yes, I know there are duplicates in the table but I plan to structure the queries such that the duplicates are ignored) but at this point am not aware of many viable options. After searching around, I thought maybe I wanted a pivot but that doesn’t seem to fit what I have here because I’m leaving the names in the column and associating them as column heads for a paired score. Then I thought maybe I wanted to store a variable as the value of each row and then add them as the columns. That was no help. My latest iteration was maybe creating a temp table as an exact copy with and identity column, then trying to select the specific name by the identity and looping through them but I can’t even seem to grab the first name and make it a column name in addition to a row value under the name column...see below
--create a table of names with an identity column
CREATE TABLE myTable2
(
ID INT IDENTITY(1,1),
Name VARCHAR(5),
);
--add names to the table from a different table
INSERT INTO myTable1 (Name)
SELECT Name
FROM myTable1
--create a temp table with the same values
SELECT ID, Name
INTO #new
FROM myTable2
GROUP BY ID, Name
--insert name from first row as a column head
INSERT INTO myTable2 (SELECT Number FROM #new WHERE ID =1)
So, in the last bit there, INSERT INTO”, I want to copy the names, in this instance “Mike” and make it ALSO a column head in the same table where it is a row (like in my second table). I get an error message that the syntax is not correct for the statement. Why isn’t this allowed? How can I get it to do what I want? It also has been suggested by someone that knows way more about this stuff than me, that maybe instead of building the table as a matrix, build it as below. It is possible here to get rid of the duplicates this way and I would except I have no idea where to even begin doing this…
Name1-----------Name2-----------Calculated Value
Mike--------------Mike-------------NULL
Jeff---------------Mike-------------100.1
Robert-------------Mike-------------5.4
Mike--------------Jeff-------------100.1
Jeff----------------Jeff-------------NULL
Robert------------Jeff-------------21.23
Mike--------------Robert-----------5.4
Jeff---------------Robert-----------21.23
Robert------------Robert-----------NULL
...etc
Any help suggestions or pointing of me in the right and most appropriate direction would be greatly appreciated!
EDIT: Here's how I solved my problem. Looks like the Cartesian product was the way to go. Thanks #Alex Kudryashev
--create a table of cross joined names
CREATE TABLE cartNames
(
Name1 VARCHAR(5),
Name2 VARCHAR(5),
);
--create two temporary tables from a source table of names
SELECT Name AS Name1
INTO #name1
FROM names
GROUP BY Name
SELECT Name AS Name2
INTO #Name2
FROM names
GROUP BY Name
--populate the Cartesian table
INSERT INTO cartNames
SELECT * FROM #name1 CROSS JOIN #name2
--get rid of the temp tables
DROP TABLE #Name1
DROP TABLE #Name2
--add columns and populate calculated scores
---
It looks like you want to create a Cartesian Product. There is very easy way to do so.
declare #tbl table(name varchar(10))
insert #tbl(name) values('MIke'),('Jeff'),('Robert')
select t1.name name1,t2.name name2, some_udf(t1.name,t2.name) calc_value
from #tbl t1 cross join #tbl t2

SQL how to create and import only specific columns from table A to a new table, table B

In Table A i have many fields like referenceid, amount, timestamp, remarks, status, balancebefore, balanceafter, frmsisdn, tomsisdn, id etc etc
I want to create a new table, Table B based of Table A(with column names, datatypes etc etc) but i only need specific columns that are in table A.
I tried select * into TableB from TableA where 1 = 2 but it says ORA-00905: missing keyword. I am using TOAD.
thank you
In Oracle, the correct syntax is create table as. SELECT INTO is used primarily in SQL Server and Sybase.
create table tableb as
select . . .
from tableA;
Only include the where clause if you don't actually want to insert any rows.
In MySQL the syntax is the same as Oracle's (see here).
Notice that the new table does not contain any constraints from the original table (indexes, keys, etc.)

INSERT a new column into an existing SQL table

I have a "source data" table with columns A,B,C,D,E,F
I use this table to populate a live table by using
INSERT INTO LIVETABLE
SELECT *
FROM SOURCEDATATABLE
Recently, a new column (C1) was added to the LIVETABLE
All I want to do is insert a C1 column into my SOURCEDATATABLE between C and D so that it now is A,B,C,C1,D,E,F. There is no need to populate with data as the LIVETABLE accepts NULLs
Is there any easy solution?
EDIT - MISSING INFORMATION
This table is one of many and my approach to using the INSERT INTO is due to having to use dynamic SQL (for various other reasons) so I cannot specify the column names
There is a reason for the Mantra "I shall not use SELECT *" and you ran straight into it. Add the column to SOURCEDATATABLE (if necessary) and enumerate the columns in the SELECT clause using NULL for the new one.
The only way to insert a new column between two columns is to create a new table with the columns in the order you want, copy the data into it, drop the old table and rename the new table with the old name. Make sure you remove primary key identities to maintain the identity column.

How copy one table contents to another, ignoring PK duplicates when i don't know column set

I have 2 databases: SRC and DST. Each one contains table DATA an in every database DATA's columns sets are equal, but it's unknown for user (I don't know name of PK or even is PK identity or single).
I already have the following script:
insert into DST.dbo.DATA select * from SRC.dbo.DATA
But if DST.DATA contains rows with same PK it throws an error (I'm using C#). That's why i want to use something like
on duplicate ignore
from mysql
Could you please advice me script that copies rows from SRC.dbo.DATA to DST.dbo.DATA ignoring primary key constraints. And if possible, foreign constraints too
Sorry for bad english
You can try something like
insert into DST.dbo.DATA
select s.*
from SRC.dbo.DATA s LEFT JOIN
DST.dbo.DATA d ON s.Keys1 = d.Keys1
AND s.Keys2 = d.Keys2
...
AND s.KeysN = d.KeysN
WHERE d.Keys1 IS NULL
This should allow you to only insert values from Source, that is not in Destination.
You can try something like this, to not select from SRC which is existing in DST.
insert into DST.dbo.DATA select * from SRC.dbo.DATA
WHERE SRC.dbo.DATA.PKColumn NOT IN(SELECT PKColumn FROM DST.dbo.DATA)

Create a unique primary key (hash) from database columns

I have this table which doesn't have a primary key.
I'm going to insert some records in a new table to analyze them and I'm thinking in creating a new primary key with the values from all the available columns.
If this were a programming language like Java I would:
int hash = column1 * 31 + column2 * 31 + column3*31
Or something like that. But this is SQL.
How can I create a primary key from the values of the available columns? It won't work for me to simply mark all the columns as PK, for what I need to do is to compare them with data from other DB table.
My table has 3 numbers and a date.
EDIT What my problem is
I think a bit more of background is needed. I'm sorry for not providing it before.
I have a database ( dm ) that is being updated everyday from another db ( original source ) . It has records form the past two years.
Last month ( july ) the update process got broken and for a month there was no data being updated into the dm.
I manually create a table with the same structure in my Oracle XE, and I copy the records from the original source into my db ( myxe ) I copied only records from July to create a report needed by the end of the month.
Finally on aug 8 the update process got fixed and the records which have been waiting to be migrated by this automatic process got copied into the database ( from originalsource to dm ).
This process does clean up from the original source the data once it is copied ( into dm ).
Everything look fine, but we have just realize that an amount of the records got lost ( about 25% of july )
So, what I want to do is to use my backup ( myxe ) and insert into the database ( dm ) all those records missing.
The problem here are:
They don't have a well defined PK.
They are in separate databases.
So I thought that If I could create a unique pk from both tables which gave the same number I could tell which were missing and insert them.
EDIT 2
So I did the following in my local environment:
select a.* from the_table#PRODUCTION a , the_table b where
a.idle = b.idle and
a.activity = b.activity and
a.finishdate = b.finishdate
Which returns all the rows that are present in both databases ( the .. union? ) I've got 2,000 records.
What I'm going to do next, is delete them all from the target db and then just insert them all s from my db into the target table
I hope I don't get in something worst : - S : -S
The danger of creating a hash value by combining the 3 numbers and the date is that it might not be unique and hence cannot be used safely as a primary key.
Instead I'd recommend using an autoincrementing ID for your primary key.
Just create a surrogate key:
ALTER TABLE mytable ADD pk_col INT
UPDATE mytable
SET pk_col = rownum
ALTER TABLE mytable MODIFY pk_col INT NOT NULL
ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)
or this:
ALTER TABLE mytable ADD pk_col RAW(16)
UPDATE mytable
SET pk_col = SYS_GUID()
ALTER TABLE mytable MODIFY pk_col RAW(16) NOT NULL
ALTER TABLE mytable ADD CONSTRAINT pk_mytable_pk_col PRIMARY KEY (pk_col)
The latter uses GUID's which are unique across databases, but consume more spaces and are much slower to generate (your INSERT's will be slow)
Update:
If you need to create same PRIMARY KEYs on two tables with identical data, use this:
MERGE
INTO mytable v
USING (
SELECT rowid AS rid, rownum AS rn
FROM mytable
ORDER BY
co1l, col2, col3
)
ON (v.rowid = rid)
WHEN MATCHED THEN
UPDATE
SET pk_col = rn
Note that tables should be identical up to a single row (i. e. have same number of rows with same data in them).
Update 2:
For your very problem, you don't need a PK at all.
If you just want to select the records missing in dm, use this one (on dm side)
SELECT *
FROM mytable#myxe
MINUS
SELECT *
FROM mytable
This will return all records that exist in mytable#myxe but not in mytable#dm
Note that it will shrink all duplicates if any.
Assuming that you have ensured uniqueness...you can do almost the same thing in SQL. The only problem will be the conversion of the date to a numeric value so that you can hash it.
Select Table2.SomeFields
FROM Table1 LEFT OUTER JOIN Table2 ON
(Table1.col1 * 31) + (Table1.col2 * 31) + (Table1.col3 * 31) +
((DatePart(year,Table1.date) + DatePart(month,Table1.date) + DatePart(day,Table1.date) )* 31) = Table2.hashedPk
The above query would work for SQL Server, the only difference for Oracle would be in terms of how you handle the date conversion. Moreover, there are other functions for converting dates in SQL Server as well, so this is by no means the only solution.
And, you can combine this with Quassnoi's SET statement to populate the new field as well. Just use the left side of the Join condition logic for the value.
If you're loading your new table with values from the old table, and you then need to join the two tables, you can only "properly" do this if you can uniquely identify each row in the original table. Quassnoi's solution will allow you to do this, IF you can first alter the old table by adding a new column.
If you cannot alter the original table, generating some form of hash code based on the columns of the old table would work -- but, again, only if the hash codes uniquely identify each row. (Oracle has checksum functions, right? If so, use them.)
If hash code uniqueness cannot be guaranteed, you may have to settle for a primary key composed of as many columns are required to ensure uniqueness (e.g. the natural key). If there is no natural key, well, I heard once that Oracle provides a rownum for each row of data, could you use that?