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.
Related
I tried using pivot in SQL Server, but I'm just going in circles with no good results.
I have this result set that could vary in number of records:
ForeignID
Name
Value
1
A
1
1
B
2
1
C
3
2
D
4
How can I do a SELECT to get this for all rows with ForeignID of 1:
ForeignID
A
B
C
1
1
2
3
This question already has answers here:
Database scheme, autoincrement
(2 answers)
Closed 3 years ago.
I have two tables: Items and Defects.
Each defect relates to one (and only one) item.
The PK for Items is an identity column (ItemID), which appears as a FK column in Defects, to relate the two tables.
The PK for Defects is an identity column (DefectID).
However there is also a subordinate numeric key in Defects called RefNo, which must be populated by a sequential number per ItemID, thus:
Defects
DefectID ItemID RefNo
1 1 1
2 1 2
3 1 3
4 2 1
5 2 2
6 3 1
7 4 1
8 3 2
9 1 4
What's the best way to populate the Ref column?
Currently the code I inherited accomplishes this in the front end which is obviously A Bad Idea.
I am starting to code an insert trigger (SQL Server 2008-R2) but wonder about atomicity and the need to potentially update more than one row when the trigger is called - and the likelihood of simultaneous inserts by different users to try and insert the same RefNo.
[Edit]
I'm maintaining an existing database and removing the RefNo column and repacing it with a value calculated on the fly is not an option.
You can use ROW_NUMBER as below to generate your refno-
WITH your_table(DefectID,ItemID,RefNo)
AS
(
SELECT 1,1,1 UNION ALL
SELECT 2,1,2 UNION ALL
SELECT 3,1,3 UNION ALL
SELECT 4,2,1 UNION ALL
SELECT 5,2,2 UNION ALL
SELECT 6,3,1 UNION ALL
SELECT 7,4,1 UNION ALL
SELECT 8,3,2 UNION ALL
SELECT 9,1,4
)
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ItemID ORDER BY DefectID) AS RefNo_new
FROM your_table
order by 2,1
Output-
DefectID ItemID RefNo RefNo_new
1 1 1 1
2 1 2 2
3 1 3 3
9 1 4 4
4 2 1 1
5 2 2 2
6 3 1 1
8 3 2 2
7 4 1 1
I have a scenario where in I want a field in a table to be incremented sequentially.
Suppose I have a table Test, with columns TestID, TestResult1,2 etc.. and TestCount.
I have data bulk inserted into the table. Some of the records may be retests, which means new data to be inserted matches existing records in the table, Test Count should be updated.Matching is done on TestID
If the table is as follows:
TestID TestResult1 TestResult2.. TestCount
12 1 1 1
12 2 2 2
13 4 1 1
Data to be inserted in
TestID TestResult1 TestResult2..
12 3 5
12 2 2
The table should be updated as
TestID TestResult1 TestResult2.. TestCount
12 1 1 1
12 2 2 2
13 4 1 1
12 3 5 3
12 2 2 4
I tried adding a trigger on the table to update the TestCount Counting the number of records that matches. But it was updating the table as follows
TestID TestResult1 TestResult2.. TestCount
12 1 1 1
12 2 2 2
13 4 1 1
12 3 5 3
12 2 2 3
CREATE TRIGGER trgTestCount
on Test
AFTER INSERT
AS
Update g
Set TestCount= (Select Count(*)+1 from Test g join INSERTED g1 where g.TestID=g1.TestID )
from Test g
This is a SSIS package and I use a dataflow task to load data from STg table to test table.
Can you tell me what I am doing wrong here?
If you can change the table structure, I would suggest adding an Identity column, change the TestCount column to a computed column, and have it's value as the count of distinct test ids that are the same is the current row test id and the create date is lower than the current value of the Identity column.
This will eliminate the need for triggers and will handle inserting multiple records with the same test id automatically.
I have values in SQL Server derived column sorted as descending i.e.
id Count OR id Count OR id Count
1 4 1 5 1 11
2 4 2 2 2 1
3 4 3 1 3 1
4 4 4 1 4 1
5 4 5 1 5 1
Now I want to select top 3 maximum values. How can I select so that query returns consistent result every time.
For example if values of Count are same which id's should be returned as top 3 maximums, similarly if 3rd value is matched with other values and if 2nd value is matched with other values then which id's should be returned by the query. And the result should be consistent every time I execute the query.
The with ties argument of the top function will return all the of the rows which match the top values:
select top (3) with ties id, count from table1
order by count desc
Alternatively, if you wanted to return 3 values only, but make sure they are always the same 3 values, then you will need to use something else as a tie-breaker. In this case, it looks like your id column could be unique.
select top (3) id, count from table1
order by count desc, id
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.