How to update 2 tables using T-SQL? - sql-server

I'm just wondering why still getting not correct result (0 row(s) affected)
with my update SQL. Please help I just need to update the Table A from Table B data with Price, and Size. After executing the update script I get 0 rows(s) affected. Why?
Table A:
TableAId CountNo Class RoomNo Section Price Sale Size
4 1 NULL 9 B 24347000 NULL NULL
5 1 NULL 9 C 26881000 NULL NULL
12 1 NULL 8 B 24245000 NULL NULL
16 1 NULL 8 A 39038000 NULL NULL
3 1 NULL 8 C 26495370 NULL NULL
21 1 NULL 6 D 36423000 NULL NULL
14 1 NULL 6 C 27200000 NULL NULL
1 1 NULL 5 C 30483000 NULL NULL
2 1 NULL 5 D 41052330 NULL NULL
Table B:
TableBId CountNo Class RoomNo Section Transaction Sale Size
12 1 NULL 9 B NULL 24347000 23800
20 1 NULL 9 C NULL 26881000 22800
44 1 NULL 9 NULL NULL 40079000 23100
69 1 NULL 9 D NULL 37614000 22100
21 1 NULL 8 C NULL 26763000 22700
28 1 NULL 8 D NULL 37444000 22000
13 1 NULL 8 B NULL 24245000 23700
5 1 NULL 8 A NULL 39038000 22500
6 1 NULL 7 A NULL 39558000 22800
Updated table:
TableAId CountNo Class RoomNo Section Price Sale Size
4 1 NULL 9 B 24347000 24347000 23800
5 1 NULL 9 C 26881000 26881000 22800
12 1 NULL 8 B 24245000 24245000 23700
16 1 NULL 8 A 39038000 39038000 22500
3 1 NULL 8 C 26495370 26763000 22700
21 1 NULL 6 D NULL NULL NULL
14 1 NULL 6 C NULL NULL NULL
1 1 NULL 5 C NULL NULL NULL
2 1 NULL 5 D NULL NULL NULL
SQL statement:
UPDATE x
SET x.Sale = y.Sale,
x.Size = y.Size
FROM TableA x
JOIN TableB y ON x.CountNo = y.CountNo
AND x.Class = y.Class
AND x.RoomNo = y.RoomNo
AND x.Section = y.Section
(0 row(s) affected)

try this: you need to compare null values separately
UPDATE x
SET
x.Sale = y.Sale,
x.Size = y.Size
FROM TableA x
JOIN TableB y
ON
x.CountNo = y.CountNo AND
(x.Class = y.Class OR (x.Class IS NULL and y.Class IS NULL)) AND
x.RoomNo = y.RoomNo AND
x.Section = y.Section

I believe that is happening because of NULL
UPDATE x
SET
x.Sale = y.Sale,
x.Size = y.Size
FROM
TableA x
JOIN TableB y ON x.CountNo = y.CountNo
AND ISNULL(x.Class,'') = ISNULL(y.Class,'')
AND x.RoomNo = y.RoomNo
AND ISNULL(x.Section,'') = ISNULL(y.Section,'')

You need add ISNULL(, ) If column is nullable
UPDATE x
SET
x.Sale = y.Sale,
x.Size = y.Size
FROM TableA x
JOIN TableB y
ON
ISNULL(x.CountNo, 0) = ISNULL(y.CountNo, 0) AND
ISNULL(x.Class, '') = ISNULL(y.Class, '') AND
ISNULL(x.RoomNo, 0) = ISNULL(y.RoomNo, 0) AND
ISNULL(x.Section, '') = ISNULL(y.Section, 0)

Related

Adding two dynamic columns in the table through stored procedure and these columns must have data based on condition

I am trying to add two dynamic columns HeaderText and IsShowHeader to my table through a stored procedure.
In the first column, the first row must have text as Header1 and after 8 rows text must be Header2, then again after 8 rows text must be Header3 and so on.
In the second column value must be 1, and next 8 rows must have 0, the 9th row value must be 1 again, then the next 8 rows must have 0 like this...
ALTER PROCEDURE [dbo].[SkipRow]
AS
BEGIN
SELECT RID
,FirstName
,LastName
,(CASE WHEN X.[Row#]%9=0 And [X].[Row#]=0 THEN 1 ELSE
0 END)As IsShowHeader
,(COUNT(*) OVER ()) as TotalRows FROM
(
SELECT
*,ROW_NUMBER() OVER(ORDER BY RID) AS [Row#]
FROM Mytable1 WITH(NOLOCK)
)X
End
Output:
HeaderText IsShowHeader
1 Header1 1
2 Null 0
3 Null 0
4 Null 0
5 Null 0
6 Null 0
7 Null 0
8 Null 0
9 Null 0
10 Header2 1
11 Null 0
12 Null 0
13 Null 0
14 Null 0
15 Null 0
16 Null 0
17 Null 0
18 Null 0
19 Header3 1
you already have the [Row#], use the modulus operator % to get every 9 rows
HeaderText = case when ([Row#] - 1) % 9 = 0
then 'Header' + convert(varchar(10), ([Row#] - 1) / 9 + 1)
end,
IsShowHeader = case when ([Row#] - 1) % 9 = 0
then 1 else 0 end
You can try this:
SELECT M.id,
M.HeaderText,
CASE WHEN M.HeaderText IS NOT NULL THEN 1 ELSE 0 END AS IsShowHeader
FROM
(
SELECT P.id,
CASE
WHEN P.HeaderText IS NOT NULL THEN
P.HeaderText + CAST(P.IndexNumber AS VARCHAR(10))
ELSE
NULL
END AS HeaderText
FROM
(
SELECT K.id,
HeaderText,
COUNT(K.HeaderText) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS IndexNumber
FROM
(
SELECT id,
CASE
WHEN (id - 1) % 9 = 0 THEN 'Header' ELSE NULL
END AS HeaderText
FROM dbo.test
) AS K
) AS P
) AS M;
I have illustrate the scenario step by step, however you can rewrite it in a simple way like the answer that #Squirrel posted.

How to perform stable sort over multiple columns?

Imagine i have a data set that contains:
Date Id
-------------- ----
11/1/2017 null
11/4/2017 3
11/5/2017 null
11/12/2017 10
null 1
null 2
null 7
null 8
null 9
I want the rows ordered so that both columns are increasing.
Using a naïve ORDER BY Date, ID does not do it:
There is an ordering
There is an ordering that satisfies the results of my desired sort order:
the date column is always increasing
the id column value is always increasing
Or course, that's not a unique ordering:
Date Id
-------------- ---------------
null 1
11/1/2017 null
null 2
11/4/2017 3
null 7
null 8
null 9
11/5/2017 null
11/12/2017 10
A programming language could do it
I know i can accomplish this on the client side. In a functional functional programming language: use a stable sorting algorithm:
A stable sort is one which preserves the original order of the input
set, where the comparison algorithm does not distinguish between two
or more items.
Consider a sorting algorithm that sorts cards by rank, but not by
suit. The stable sort will guarantee that the original order of cards
having the same rank is preserved; the unstable sort will not.
Unfortunately i have
9.1 million rows
1.8 GB
of monotonically increasing rows to put in best possible chronological sort order. Obviously i'd prefer to do this on the server - which is well suited to handling large amounts of data.
How can i perform a stable-sort in SQL Server?
Example Data
Example SQL Fiddle
CREATE TABLE #SortDemo (Date datetime NULL, Id int NULL)
INSERT INTO #SortDemo (Date, Id)
VALUES
('20171101', null),
('20171104', 3),
('20171105', null),
('20171112', 10),
(null, 1),
(null, 2),
(null, 7),
(null, 8),
(null, 9)
SELECT * FROM #SortDemo
ORDER BY Date, Id
It is a solvable problem. You don't have to throw your hands up and say computers cannot be used to solve problems.
Start with the data, and add a new surrogate "Rank" column.
Date Id Rank
-------------- ---- ----
null 7 null
null 1 null
null 9 null
null 2 null
null 8 null
11/1/2017 null null
11/4/2017 3 null
11/5/2017 null null
11/12/2017 10 null
11/13/2017 null null
Then seed Rank to the Id:
UPDATE SortDemo SET Rank = Id
WHERE Id IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null null
11/4/2017 3 3
11/5/2017 null null
11/12/2017 10 10
11/13/2017 null null
Then for the remaining items items with a Date, we need to assign it to the "next" rank:
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null null <-- 3
11/4/2017 3 3
11/5/2017 null null <-- 10
11/12/2017 10 10
11/13/2017 null null <-- ?
with
UPDATE SortDemo SET Rank = (
SELECT MIN(Rank) FROM SortDemo s2
WHERE s2.Date >= SortDemo.Date)
WHERE SortDemo.Date IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null 3 <--
11/4/2017 3 3
11/5/2017 null 10 <--
11/12/2017 10 10
11/13/2017 null null <-- ?
There's also the edge case where there are no items "after" us; which we can fix by going backwards to one the highest previous rank:
UPDATE SortDemo SET Rank = (
SELECT MAX(Rank) FROM SortDemo s2
WHERE s2.Date <= SortDemo.Date)
WHERE SortDemo.Date IS NOT NULL
Date Id Rank
-------------- ---- ----
null 7 7
null 1 1
null 9 9
null 2 2
null 8 8
11/1/2017 null 3
11/4/2017 3 3
11/5/2017 null 10
11/12/2017 10 10
11/13/2017 null 10 <--10
And we're done
We can now sort by surrogate Rank, and break ties by sorting by Date:
SELECT * FROM SortDemo
ORDER BY Rank, Date
Date Id Rank
-------------- ---- ----
null 1 1
null 2 2
11/1/2017 null 3
11/4/2017 3 3
null 7 7
null 8 8
null 9 9
11/5/2017 null 10
11/12/2017 10 10
11/13/2017 null 10
Solution complete. Sql Fiddle
The answer is in escrow until Monday, so i can give people the opportunity to earn reputation for solving a unique problem.

Escaping Null Values From Quartile in SQl Server

I have create a table and inserted some records.
CREATE TABLE #t
(
ID INT IDENTITY(1,1) PRIMARY KEY,
val INT NULL
);
-- INSERT 10 values: 3 NULL, 7 integers
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT NULL;
INSERT INTO #t SELECT 5;
INSERT INTO #t SELECT 7;
INSERT INTO #t SELECT 8;
INSERT INTO #t SELECT 9;
INSERT INTO #t SELECT 9;
INSERT INTO #t SELECT 11;
INSERT INTO #t SELECT 12;
Now when i am executing script to find quartile
SELECT *,
NTILE(4) OVER (ORDER BY val) As Q
FROM #t;
i am getting values as
ID val Q
---------
1 NULL 1
2 NULL 1
3 NULL 1
4 5 2
5 7 2
6 8 2
7 9 3
8 9 3
9 11 4
10 12 4
I don't want "Null" records and don't want to use "Where" clause.
I want result like this
ID val Q
---------
4 5 1
5 7 1
6 8 2
7 9 2
8 9 3
9 11 3
10 12 4
It strikes me that you might want NULL for the NTILE() value and to ignore the values for the calculation. You can get this by doing:
SELECT t.*,
(CASE WHEN val IS NOT NULL
THEN NTILE(4) OVER (PARTITION BY (CASE WHEN val IS NOT NULL THEN 'NOTNULL' ELSE 'NULL' END)
ORDER BY val
)
END) as Q
FROM #t t;
Or, perhaps more simply:
SELECT id, val, NTILE(4) OVER (ORDER BY val) As Q
FROM #t t
WHERE val IS NOT NULL
UNION ALL
SELECT id, val, NULL as q
FROM #t t
WHERE val IS NULL;
You could try this:
SELECT *,
CASE
WHEN val IS NULL THEN NULL
ELSE NTILE(4) OVER (
--Split NULL and NOT NULL into 2 different groups
PARTITION BY CASE WHEN val IS NULL THEN 0 ELSE 1 END
ORDER BY val)
END AS Q
FROM #t
You'll get:
ID val Q
1 NULL NULL
2 NULL NULL
3 NULL NULL
4 5 1
5 7 1
6 8 2
7 9 2
8 9 3
9 11 3
10 12 4

TSQL Selection Criteria For Join - Left Join

Select *
From cacheAttendanceMeasures cam
Left Join dmcUserSelectedAttendanceMeasures usam on usam.attMeasureID = cam.attMeasureID
And usam.personID = #personID
And usam.pageID = #pageID
I understand that the above query will return all rows from cacheAttendanceMeasures as well as any rows from dmcUserSelectedAttendanceMeasures and dmcUserSelectedStudentMonths where the conditions match. What I would really like it to do is this:
If the left join(s) don't match, then return all rows from cacheAttendanceMeasures -- so what it is currently doing
However, if the left join(s) DO match, then return ONLY the rows that match from cacheAttendanceMeasures
Is this possible?
EDIT:
I simplified the query above to only include one Left Join table, I don't want to over-complicate the issue.
Below are dataset examples I'd like to see returned based on if there are no matches between the tables versus there is a match:
cam Table
cID attMeasureID Value
1 1 530
2 2 95.7
3 3 380
4 4 742.57
5 5 200
usam Table
uID personID pageID attMeasureID
1 877450 31 1
2 923450 28 2
3 877450 31 3
4 369842 28 4
5 212193 25 1
Dataset to Return if #personID = 577597 & #pageID = 20:
CID attMeasureID Value uID pageID attMeasureID
1 1 530 null nul null
2 2 95.7 null null null
3 3 380 null null null
4 4 742.57 null null null
5 5 200 null null null
Dataset to Return if #personID = 877450 & #pageID = 31:
CID attMeasureID Value uID personID pageID attMeasureID
1 1 530 1 877450 31 1
3 3 380 3 877450 31 3
I'm not really sure what results you want...
At first I thought maybe something like this..
SELECT *
FROM cacheAttendanceMeasures cam
LEFT JOIN dmcUserSelectedAttendanceMeasures usam
on usam.attMeasureID = cam.attMeasureID
And usam.personID = #personID
And usam.pageID = #pageID
LEFT JOIN dmcUserSelectedStudentMonths ussm
on ussm.monthSeq = cam.pupilMonth
And ussm.personID = USAM.PersonID
And ussm.pageID = USAM.PageId
--This where clause would seem silly as it negates the left joins; making them inner joins and violates #1 as to what you're after. so I don't think that's what you're after...
WHERE ussm.personID is not null
and usam.personID is not null
So with rule 2 are you saying... if a single record isn't null, then only return records which exist in both Left joined tables and the 1st table?
So given:
T1 T2 T3
X X X
Y NULL Y
Z Y NULL
T NULL NULL
I think you would want just record X
But Given
So given:
T1 T2 T3
X X NULL
Y NULL Y
Z Y NULL
T NULL NULL
I think you would want X, Y Z, and T... need better clairification.

SQL SERVER : populating a column based on other other columns

I have a tableA: (ID int, matchPID char,PID char, set int, num char, QID char, QStatus char)
ID matchPID PID set num QID QStatus
1 00001230 xx123 1 234
2 00001229 xx234 1 214
3 00000054 xx654 1 NULL
4 00012000 xx125 2
5 00A53214 xx321 2
6 00000100 xx213 2
matchPID is always (00-xxxxxx) x can be char or int.
now I have to populate OID just one value for each set according to [num].
If for any set, there exists any value in [num], then populate OID with PID where exists [num] for same set and populate Qstatus = 'fail' in rest.
so OID can be populated in id 1 or 2. (any1), then check lowest matchPID and populate here. so in this case (set1) expected result is :
ID matchPID PID set num QID QStatus
1 00001230 xx123 1 234 NULL FAIL
2 00001229 xx234 1 214 xx234 NULL
3 00000054 xx654 1 NULL NULL FAIL
if for any set there isnt any [num] found, then pick lowest matchPID and populate QID with PID and fail the rest.
notice that matchPID starts with 00 and then it can be 0>1>2>..>A>B>C>....
so expected result for set2 is :
ID matchPID PID set num QID QStatus
4 00012000 xx125 2 NULL NULL FAIL
5 00A53214 xx321 2 NULL NULL FAIL
6 00000100 xx213 2 NULL xx213 NULL
Thanks
Did you want something like this?:
;WITH setInfo AS (
SELECT [SET],
CASE WHEN EXISTS (SELECT 1 FROM tableA b
WHERE b.[set]=a.[set] AND num IS NOT NULL)
THEN 1 ELSE 0 END AS HasNum,
MIN(matchPID) AS MinMatchPID
FROM tableA a
GROUP BY [SET]
)
UPDATE a SET
QID = CASE WHEN s.HasNum = 0 AND a.matchPID = s.MinMatchPID THEN a.PID
WHEN s.HasNum = 0 AND a.matchPID != s.MinMatchPID THEN NULL
WHEN s.HasNum = 1 AND a.matchPID = (SELECT min(matchpid) FROM tableA b
WHERE b.[set] = a.[set]
AND b.num is not null
)
THEN a.PID
ELSE NULL
END,
QStatus = CASE WHEN s.HasNum = 0 AND a.matchPID = s.MinMatchPID THEN NULL
WHEN s.HasNum = 0 AND a.matchPID != s.MinMatchPID THEN 'FAIL'
WHEN s.HasNum = 1 AND a.matchPID = (SELECT min(matchpid) FROM tableA b
WHERE b.[set] = a.[set]
AND b.num is not null
)
THEN a.PID
ELSE 'FAIL'
END
FROM tableA a
JOIN setInfo s ON s.[set] = a.[set]

Resources