how to update foreign key - sql-server

I have 2 tables; design of first table is like below:
Table 1:
id_Doc_line_sheet (pk),Autonumber
DocNo (text)
lineNo (text)
Sheet No (text)
Combination of fields (DocNo, lineNo, Sheet No) is index and unique.
Design of second table is like below:
Table 2:
id_Doc_line_trans (pk), Autonumber
id_Doc_line_sheet (fk),Number
name
Now in table1, for the field lineNo I have records with leading spaces and without leading spaces like below:
id_Doc_line_sheet DocNo lineNo Sheet No
------------------------------------------------------------------
1001 doc-0001 line-0001 1
1002 doc-0001 line-0001 1
1003 doc-0001 line-0001 2
1004 doc-0001 line-0001 2
1005 doc-0002 line-0002 1
1006 doc-0002 line-0002 1
1007 doc-0001 line-0005 1
1008 doc-0001 line-0005 1
And I want deleted these records with leading spaces but at first I want to update (id_Doc_line_sheet) for each unique (DocNo,lineNo,Sheetno) to correct one (without leading space).
I mean if the table2 is like below:
id_Doc_line_trans id_Doc_line_sheet name
---------------------------------------------------
1 1001 name01
2 1002 name02
3 1003 name03
4 1004 name04
5 1007 name07
6 1008 name08
I update (id_Doc_line_sheet) to something like below:
id_Doc_line_trans id_Doc_line_sheet name
---------------------------------------------------
1 1001 name01
2 1001 name02
3 1003 name03
4 1003 name04
5 1007 name07
6 1007 name08
And then delete records with leading spaces from first table.
Please help how I can do it?

Based on what I understood, it seems you want to update the table2 based on the sheet_no first id used. If so, you can use the following:
Explanation
You need to get the first record in table1 based on the sheet_no using report cte
Find the corresponding sheet_no for each row in table2
Update the table2 entries where row_number =1
Query
;with report as(
select row_number() over(partition by sheet_no order by id_doc_line_sheet) as [Row],id_doc_line_sheet,sheet_no
from table1
where line_no not like ' %' -- here you can ensure that lin_no doesn't start with leading space
), combined as(
select t2.id_doc_line_trans,
t2.id_doc_line_sheet,
t1.sheet_no
from table2 t2
inner join table1 t1 on t2.id_doc_line_sheet = t1.id_doc_line_sheet
)
update t set t.id_doc_line_sheet = r.id_doc_line_sheet
from report r
inner join combined c on r.sheet_no = c.sheet_no
inner join table2 t on t.id_doc_line_trans = c.id_doc_line_trans
where r.[Row]=1
result after updating table2
id_doc_line_trans id_doc_line_sheet name
1 1001 name01
2 1001 name02
3 1003 name03
4 1003 name04
Then you can apply the delete statement based on your requirements
Here a working demo
Hope this will help you

Here is an approach which does not use analytic functions, which was the easiest way to approach this in my mind. We can aggregate over table1 and pivot out both the id of the records both with and without leading whitespace. Also, we can check to make sure a given document/sheet even has such a page occurring. Then, all we need to do is join table2 to this first CTE to get the old and new id values in a single record.
WITH cte1 AS (
SELECT
DocNo, [Sheet No],
MAX(CASE WHEN [lineNo] LIKE ' %' THEN id_Doc_line_sheet END) AS id_old,
MAX(CASE WHEN [lineNo] NOT LIKE ' %' THEN id_Doc_line_sheet END) AS id_new
FROM table1
GROUP BY DocNo, [Sheet No]
HAVING SUM(CASE WHEN [lineNo] LIKE ' %' THEN 1 ELSE 0 END) > 0
),
cte2 AS (
SELECT
t1.id_Doc_line_trans, t1.id_Doc_line_sheet, t1.name, t2.id_old, t2.id_new
FROM table2 t1
INNER JOIN cte1 t2
ON t1.id_Doc_line_sheet = t2.id_old
)
UPDATE cte2
SET id_Doc_line_sheet = id_new;
Note that the update logic is trivial; all the information and records of interest were already included in the second CTE.
Demo

Related

how to update foreign key that depends on 3 field in primary table

before i had a similar question for update foreign key that depends on 2 fields in primary table, how to update foreign key
after getting answer and testing in my database, i saw it did not solve my problem, actually the answer i received assume for each Doc No, Sheet No, i have similar Line no (with leading space or not leading space) but in my database i have different line no for each Doc No, Sheet No (as i edited in my question) so i modified my question and sample data like below for getting new Answer:
I have 2 tables; design of first table is like below:
Table 1:
id_Doc_line_sheet (pk),Autonumber
DocNo (text)
lineNo (text)
Sheet No (text)
Combination of fields (DocNo, lineNo, Sheet No) is index and unique.
Design of second table is like below:
Table 2:
id_Doc_line_trans (pk), Autonumber
id_Doc_line_sheet (fk),Number
name
Now in table1, for the field lineNo I have records with leading spaces and without leading spaces like below:
id_Doc_line_sheet DocNo lineNo Sheet No
------------------------------------------------------------------
1001 doc-0001 line-0001 1
1002 doc-0001 line-0001 1
1003 doc-0001 line-0001 2
1004 doc-0001 line-0001 2
1005 doc-0002 line-0002 1
1006 doc-0002 line-0002 1
1007 doc-0001 line-0005 1
1008 doc-0001 line-0005 1
And I want deleted these records with leading spaces but at first I want to update (id_Doc_line_sheet) for each unique (DocNo,lineNo,Sheetno) to correct one (without leading space).
I mean if the table2 is like below:
id_Doc_line_trans id_Doc_line_sheet name
---------------------------------------------------
1 1001 name01
2 1002 name02
3 1003 name03
4 1004 name04
5 1007 name07
6 1008 name08
I update (id_Doc_line_sheet) to something like below:
id_Doc_line_trans id_Doc_line_sheet name
---------------------------------------------------
1 1001 name01
2 1001 name02
3 1003 name03
4 1003 name04
5 1007 name07
6 1007 name08
And then delete records with leading spaces from first table.
Please help how I can do it?
Based on the new requirements you provided
Here what you can do
Find all the lines with no leading space, this is where report cte was used for
apply the result report to the table1 by joining the sheet_no and doc_no and line_no of table = ' ' + report.line_no + % , here where combined cte was used
update the table2 based on the id_doc_line_sheet of the combined replaceId
Query
;with report as(
select t.id_doc_line_sheet, sheet_no,doc_no,line_no
from #table1 t
where t.line_no not like ' %'
), combined as(
select isnull(x.id_doc_line_sheet,t.id_doc_line_sheet) replaceId, t.id_doc_line_sheet,t.doc_no,t.line_no,t.sheet_no
from #table1 t
left join report x on x.sheet_no = t.sheet_no and
x.doc_no = t.doc_no and
t.line_no like ' ' + x.line_no + '%'
)
update t2 set t2.id_doc_line_sheet = c.replaceId
from #table2 t2
inner join combined c on c.id_doc_line_sheet = t2.id_doc_line_sheet
Here a working demo
Result
id_doc_line_trans id_doc_line_sheet name
1 1001 name01
2 1001 name02
3 1003 name03
4 1003 name04
5 1007 name07
6 1007 name08
If this is not what you are looking for, kindly explain in more details the criteria how the query should update the table2.
Hope this will help you

How to get non matching records in sql server in same table?

I have a table say StudentBillDetails and in this table data is saved annually and yrid is referenced to some other table. Now I am stuck with a problem. I want to retrieve non matching records as described below.
Stid BillNo Yrid
1 525 3
1 525 1
1 525 4
2 443 4
2 442 1
2 443 3
In above given table structure as you can see for three years StId 1 has same value but StId 2 has a confliction in Yrid 1. So I want to get these type of records.
If you just want to flag Stid values which have conflicts then the following simple query should work:
SELECT Stid
FROM yourTable
GROUP BY Stid
HAVING COUNT(DISTINCT BillNo) > 1
If you want the entire records you could try joining your table to the above query:
SELECT t1.*
FROM yourTable t1
INNER JOIN
( SELECT Stid FROM yourTable GROUP BY Stid HAVING COUNT(DISTINCT BillNo) > 1 ) t2
ON t1.Stid = t2.Stid

SQL Server query involving subqueries - performance issues

I have three tables:
Table 1: | dbo.pc_a21a22 |
batchNbr Other columns...
-------- ----------------
12345
12346
12347
Table 2: | dbo.outcome |
passageId record
---------- ---------
00003 200
00003 9
00004 7
Table 3: | dbo.passage |
passageId passageTime batchNbr
---------- ------------- ---------
00001 2015.01.01 12345
00002 2016.01.01 12345
00003 2017.01.01 12345
00004 2018.01.01 12346
What I want to do: for each batchNbr in Table 1 get first its latest passageTime and the corresponding passageID from Table 3. With that passageID, get the relevant rows in Table 2 and establish whether any of these rows contains the record 200. Per passageId there are at most 2 records in Table 2
What is the most efficient way to do this?
I have already created a query that works, but it's awfully slow and thus unfit for tables with millions of rows. Any suggestion on how to either change the query or do it another way? Altering the table structure is not an option, I only have read rights to the database.
My current solution (slow):
SELECT TOP 50000
a.batchNbr,
CAST ( CASE WHEN 200 in (SELECT TOP 2 record FROM dbo.outcome where passageId in (
SELECT SubqueryResults.passageId From (SELECT Top 1 passageId FROM dbo.passage pass WHERE pass.batchNbr = a.batchNbr ORDER BY passageTime Desc) SubqueryResults
)
) then 1 else 0 end as bit) as KGT_IO_END
FROM dbo.pc_a21a22 a
The desired output is:
batchNbr 200present
--------- ----------
12345 1
12346 0
I suggest you use table joining rather than subqueries.
select
a.*, b.*
from
dbo.table1 a
join
dbo.table2 b on a.id = b.id
where
/*your where clause for filtering*/
EDIT:
You could use this as a reference Join vs. sub-query
Try this
SELECT TOP 50000 a.*, (CASE WHEN b.record = 200 THEN 1 ELSE 0 END) AS
KGT_IO_END
FROM dbo.Test1 AS a
LEFT OUTER JOIN
(SELECT record, p.batchNbr
FROM dbo.Test2 AS o
LEFT OUTER JOIN (SELECT MAX(passageId) AS passageId, batchNbr FROM
dbo.Test3 GROUP BY batchNbr) AS p ON o.passageId = p.passageId
) AS b ON a.batchNbr = b.batchNbr;
The MAX subquery is to get the latest passageId by batchNbr.
However, your example won't get the record 200, since the passageId of the record with 200 is 00001, while the latest passageId of the batchNbr 12345 is 00003.
I used LEFT OUTER JOIN since the passageId from Table2 no longer match any of the latest passageId from Table3. The resulting subquery would have no records to join to Table1. Therefore INNER JOIN would not show any records from your example data.
Output from your example data:
batchNbr KGT_IO_END
12345 0
12346 0
12347 0
Output if we change the passageId of record 200 to 00003 (the latest for 12345)
batchNbr KGT_IO_END
12345 1
12346 0
12347 0

sql server 2012 merge values from two tables

I have two tables
tblA(sn, ID int pk, name varchar(50), amountA decimal(18,2))
and
tblB(ID int fk, amountB decimal(18,2))
here: tblA occures only once and tblB may occure multiple time
I need the query to display data like:
sn ID name AmountA amountB Balance
1 1001 abc 5000.00 5000.00
2 1002 xyz 10000.00
1002 4000.00 6000.00 (AmountA-AmountB)
3 1003 pqr 15000.00
1003 4000.00
1003 3000.00
1003 2000.00 6000.00 (AmountA-sum(AmountB))
Please ask if any confusion
I tried using lag and lead function but I couldnot get the desire result, Please help.
Since you are using SQL Server 2012, you can use a partition with an aggregate function (SUM):
SELECT t.sn,
t.ID,
t.name,
t.credits AS AmountA,
t.debits AS amountB,
SUM(t.credits - t.debits) OVER (PARTITION BY t.ID ORDER BY t.debits, t.credits) AS Balance
FROM
(
SELECT sn,
ID,
name,
AmountA AS credits,
0 AS debits
FROM tblA
UNION ALL
SELECT 0 AS sn,
ID,
NULL AS name,
0 AS credits,
amountB AS debits
FROM tblB
) t
ORDER BY t.ID,
t.debits,
t.credits
Explanation:
Since the records in tables A and B each represent a single transaction (i.e. a credit or debit), using a UNION query to bring both sets of data into a single table works well here. After this, I compute a rolling sum using the difference between credit and debit, for each record, for each ID partition group. The ordering is chosen such that credits appear at the top of each partition while debits appear on the bottom.

T-SQL select rows by oldest date and unique category

I'm using Microsoft SQL. I have a table that contains information stored by two different categories and a date. For example:
ID Cat1 Cat2 Date/Time Data
1 1 A 11:00 456
2 1 B 11:01 789
3 1 A 11:01 123
4 2 A 11:05 987
5 2 B 11:06 654
6 1 A 11:06 321
I want to extract one line for each unique combination of Cat1 and Cat2 and I need the line with the oldest date. In the above I want ID = 1, 2, 4, and 5.
Thanks
Have a look at row_number() on MSDN.
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY date_time, id) rn
FROM mytable
) q
WHERE rn = 1
(run the code on SQL Fiddle)
Quassnoi's answer is fine, but I'm a bit uncomfortable with how it handles dups. It seems to return based on insertion order, but I'm not sure if even that can be guaranteed? (see these two fiddles for an example where the result changes based on insertion order: dup at the end, dup at the beginning)
Plus, I kinda like staying with old-school SQL when I can, so I would do it this way (see this fiddle for how it handles dups):
select *
from my_table t1
left join my_table t2
on t1.cat1 = t2.cat1
and t1.cat2 = t2.cat2
and t1.datetime > t2.datetime
where t2.datetime is null

Resources