Copying SQL database and fixing foreign keys - sql-server

I am making an application which optimizes routes (kind of like a VRP). The user must be able to copy all input data, and make changes to this data. This way, they are able to find out what the impact is on the optimization.
Therefore I chose to let them be able to copy all input data, and have sort of like a version management of the data.
I want to copy the following tables:
TableOne
ID UUID WEIGHT CODE
1 abc 15 AB
2 abd 5 AC
TableTwo
ID UUID SIZE TABLE1_FK
1 abe 1 1
2 abf 3 2
The resulting tables (after copying):
TableOne
ID UUID WEIGHT CODE
1 abc 15 AB
2 abd 5 AC
3 abg 15 AB
4 abh 5 AC
TableTwo
ID UUID SIZE TABLE1_FK
1 abe 1 1
2 abf 3 2
3 abi 1 1
4 abj 3 2
Up to this point, I can manage. But now when I want to update the foreign keys of TableTwo to point to the copied lines in TableOne, I get stuck.
I want to do something like:
UPDATE TableOne
SET TABLE1_FK =
(SELECT t.ID
FROM TableOne t
WHERE t.WEIGHT = (SELECT t.WEIGHT
FROM TableOne t1
WHERE ...)
)
And this is where I get stuck.
The wanted result is:
TableTwo
ID UUID SIZE TABLE1_FK
1 abe 1 1
2 abf 3 2
3 abi 1 3
4 abj 3 4
Any suggestions?

After you insert in the first table , select it's ##IDENTITY and use it to insert
in the second table as foreign key.

Related

SQLite Join Tables With Different Primary Key Values

I have two tables in SQLITE one table FastData records data at a high rate while the other table SlowData records data at a lower rate. FastData and SlowData share a primary key (PK) that represents time of data capture. As such the two tables could look like:
Fast Data Slow Data
Pk Value1 Pk Value2
2 1 1 1
3 2 4 2
5 3 7 3
6 4
7 5
9 6
I would like to create a Select statement that joins these two tables filling in the SlowData with the previous captured data.
Join Data
Pk Value1 Value2
2 1 1
3 2 1
5 3 2
6 4 2
7 5 3
9 6 3
You may try the following approach which uses row_number to determine the most recent entry as it relates to Pk as the ideal entry for Value2 after performing a left join.
SELECT
Pk,
Value1,
Value2
FROM (
SELECT
f.Pk,
f.Value1,
s.Value2,
ROW_NUMBER() OVER (
PARTITION BY f.Pk, f.Value1
ORDER BY s.Pk DESC
) rn
FROM
fast_data f
LEFT JOIN
slow_data s ON f.Pk >= s.Pk
) t
WHERE rn=1;
Pk
Value1
Value2
2
1
1
3
2
1
5
3
2
6
4
2
7
5
3
9
6
3
View working demo on DB Fiddle
You need a LEFT join of the tables and FIRST_VALUE() window function to pick Value2:
SELECT DISTINCT f.Pk, f.Value1,
FIRST_VALUE(s.Value2) OVER (PARTITION BY f.Pk ORDER BY s.Pk DESC) Value2
FROM FastData f LEFT JOIN SlowData s
ON s.Pk <= f.Pk;
See the demo.

Update only Top 1 OR anyone row of a table using join with another table

I want to Update only top 1 OR only 1 row of a column where a column values are same.
(Just logical explanation don't go on syntax)
LIKE:
Update [Total] = (value from a another table with a common column)
but need to update only top 1 row OR any one row to the current (updating) table not all rows matching column value...
e.g
Table 1:
Skill Value
abc 3
def 4
xyz 3.5
Table 2:
Name Skill MyValue MyValue2(ColumnNeedsToBeUpdated)
Ram abc 3
shyam abc 4
Mohan abc 5
Raju xyz 4
Ratan xyz 6
Now I want to Update MyValue2 based on Table1 column Skill Value = MyValue2 but I want to update anyone OR top 1 row in Table2 NOT ALL Please help
Expected Output:
Name Skill MyValue MyValue2(ColumnNeedsToBeUpdated)
Ram abc 3 3
shyam abc 4
Mohan abc 5
Raju xyz 4 3.5
Ratan xyz 6
OR Alternate output can be:
Name Skill MyValue MyValue2(ColumnNeedsToBeUpdated)
Ram abc 3 Value from Table1 / no. of records with skill abc (3/3)
shyam abc 4
Mohan abc 5
Raju xyz 4 Value from Table1 / no. of records with skill xyz (3.5/2)
Ratan xyz 6
In Table 2, give a row number based on group by Skill column and order by MyValue column. And then updated the rows which having row number1 with Value from Table 1.
Query
;with cte as(
select [rn] = row_number() over(
partition by Skill
order by [MyValue]
), *
from [Table2]
)
update t1
set t1.[MyValue2] = t2.[Value]
from cte t1
join [Table1] t2
on t1.[Skill] = t2.[Skill]
where t1.[rn] = 1;

MSSQL Can a column auto-increment only under certain circumstances

I have a table with 4 columns ID, c1, c2 and LOT. ID is the primary key. For every record when c1 is 5 I want to auto-generate a number for LOT which will be a sequence starting from 1 for each distinct value of c2.
So if c1 is not 5, LOT remains null. But if c1 is 5 then for every record where c2=1 I want to populate LOT with an auto-incrementing sequence starting from 1.
Ex:
ID c1 c2 LOT
1 3
2 5 1 1
3 5 1 2
4 5 1 3
5 4
Then do the same for a different value of c2. So if c2 is 2, have another bunch of auto-incrementing LOT numbers starting from 1:
ID c1 c2 LOT
6 3
7 5 2 1
8 5 1 4
9 5 2 2
10 5 2 3
We are using MSSQL 2014 Enterprise Ed. Would table-partitioning be useful or do I need to create special tables for each distinct value of C2?
not with an identity field, you can use a trigger instead.
There is no way of doing this using the Identity feature, however, consider using a Instead of trigger to manually manage the values like you want.
You could use the logic to generate LOT in a query or view:
SELECT ID, C1, C2,
CASE
WHEN C1<>5 OR C2 IS NULL THEN NULL
ELSE COUNT(*) OVER (PARTITION BY C1, C2 ORDER BY ID ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
END AS LOT
FROM D
ORDER BY ID
Given a table generated with (ID, C1, C2):
CREATE TABLE D (ID INT PRIMARY KEY IDENTITY, C1 INT, C2 INT)
INSERT D VALUES (3,NULL),
(5,1),
(5,1),
(5,1),
(4,NULL),
(3,NULL),
(5,2),
(5,1),
(5,2),
(5,2)
The query produces the output indicated above:
ID C1 C2 LOT
1 3
2 5 1 1
3 5 1 2
4 5 1 3
5 4
6 3
7 5 2 1
8 5 1 4
9 5 2 2
10 5 2 3
The statement used to generate LOT, COUNT(*) OVER (PARTITION BY C1, C2 ORDER BY ID ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, simply counts the number of rows before and including the current row where C1 and C2 are equal to the current row. For instance, for Row 4, the tuple (c1,c2)=(5,1) is observed in 3 records before and including that row (rows 2, 3, and 4), so LOT=3.
Thank you everyone for the suggestions to use a trigger (all up-voted). It turns out (as I mentioned in a comment above) an article that came up on the side-bar (SQL Server unique auto-increment column in the context of another column) shows a detailed construction of the proper INSTEAD OF INSERT trigger. The author mentions that it is "Not tested", and indeed there IS a slight error (a missing GROUP BY ParentEntityID in the WITH clause) but anybody copying the code would get an error that is obvious to fix. Probably not kosher to be correcting that post here, but the other question is 6 years old.

i have 4 table in sql and i want the data or all the table where one unique key is matched in four of them

I have a table ratings, bookmark, checkin, food in food table there is a unique key sno and this sno key is used in remaining three tables.
food table
sno name totalrating totalcheckin
1 nitesh 52 45
2 abhishek 4 9
3 divye 42 30
ratings table
sno datakey rated name
1 3 3.0 divye
1 6 4.0 shashank
bookmark table
sno datakey name
1 3 divye
1 6 shashank
Checkin table
sno datakey name
1 2 abhishek
1 6 shashank
I need data where datakey is 3 if not present show null values and data key column not repeated
like
0 1 2 3 4 5 6 7 8 9 10
sno name totalrating totalcheckin sno rated name sno name sno name
3 divye 42 30 1 3.0 divye 1 divye null null
your query should look like this:
SELECT f.sno, f.name, f.totalrating, f.totalcheckin,
r.sno, r.rated, r.name,
b.sno, b.name,
c.sno, c.name
FROM food AS f
LEFT JOIN ratings AS r
ON f.sno = r.datakey
LEFT JOIN bookmark AS b
ON f.sno = b.datakey
LEFT JOIN checkin AS c
ON f.sno = c.datakey
WHERE f.sno = 3
Here is SQL Fiddle to see how it's work.
Also I agree with the guys in the comment which are told you to read something about JOIN syntax. It's pretty and you can start here, or more specific for your problem is LEFT JOIN, that is the begin and good place to start. Also you can see that I use aliases in my query about that read here.
GL!
P.S. (edit) and if you have any question fill free to ask... Also I notice that you have name column in every table, if I understand relation between your table it's not necessary. You should store name only in first table (food) and with simple JOIN from there you can pull that data whenever you need it!

How to use generate Id for different values in calculated columns?

I have a big query (which is already ordered as per my needs), one of the columns is calculated (varchar combination of other columns in the query). I need an incremental integer to identify this calculated column (duplicates should have the same id).
I canĀ“t use rank because the order in which I need the incremental number uses another criteria than the one used to generate the calculated column.
This is what I need:
OrderByColumn CalculatedColumn GeneratedId
1 ggg 1
1 aaa 2
1 ggg 1
1 fff 3
2 vvv 4
2 ddd 5
3 ggg 1
4 rrr 6
5 aaa 2
5 ooo 7
5 kkk 8
8 vvv 4
9 aaa 2
Use
ROW_NUMBER() OVER (PARTITION BY XXX ORDER BY YYY)
assuming you are using SQL2005 or better
http://msdn.microsoft.com/en-us/library/ms186734.aspx
-- though like you said this doesn't solve your dupes with same ID thing - ahhh! Give me a moment - should be able to do this pretty easy
Edit:
Here you go -
http://sqlfiddle.com/#!3/2f014/2
-- Select stuff:
select vals.val as genid, ord.* from ord
-- Join back to a distinct list of CalculatedColumn with a row_number() to id them
inner join
(select calculatedcolumn, row_number() over (order by calculatedcolumn) as val from ord group by calculatedcolumn) as vals on vals.calculatedcolumn = ord.calculatedcolumn
order by ord.orderbycolumn
Of course this is using the calculated column in the subquery - so you will need to re-calculate unless you store the value in a temp table or table variable

Resources