How to write trigger to generate sequence number for repeated value - sql

I need to generate sequence number for repeated value in a SQL Server table.
Here's my table
CREATE TABLE [dbo].[tbl_all_purple_flag_level](
[Sno] [int] IDENTITY(1,1) NOT NULL,
[Id] [varchar](50) NULL,
[Name] [varchar](50) NULL,
[Score] [varchar](50) NULL,
[Disability_Level] [varchar](50) NULL,
[visited_count] [varchar](50) NULL,
[Date] [varchar](50) NULL
)
If id has repeated numbers, I need visited_count to be a sequence number (1, 2, 3...)
I tried this code
SELECT
id,
RIGHT('0'+ CAST((ROW_NUMBER() OVER (Partition By id Order By id)) as varchar(2)), 2) as duplicate_id
FROM
tbl_all_purple_flag_level
It works fine but I don't know how to do in trigger. Can anyone help me? Thanks!

ALTER TRIGGER tr_After_Update_Inser
ON [dbo].[tbl_all_purple_flag_level]
FOR INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
WITH Updateable
AS
(
SELECT [Sno], id, [visited_count],
RIGHT('0'+ CAST((ROW_NUMBER() OVER (Partition By id Order By id, [Date] DESC)) as varchar(2)), 2) as duplicate_id
FROM tbl_all_purple_flag_level
)
UPDATE Updateable
SET [visited_count] = duplicate_id
END
One thing I would like to point out, SQL Server has Data types to store almost all kinds of data, I can see you are saving Dates in Varchar data type and IDs and Score all in varchar data type, Sql Server has Date data type to store date values. why would you use varchar for all the columns dont know but I think you should consider using appropriate data types for your column instead of using VARCHAR for everything.

Related

Searching 13 million records using full text search with additional conditions

Performance issue while doing SQL Server full text search with additional conditions. (SQL Server 2012)
I am trying to filter the data based on search filters list (table value parameter), which will return all the records for match filters and single record for the filter doesn't have any record from tables.
Full text search index is already on table Names for column SNAME.
In stored procedure, table type parameter SearchFilter is used to pass list of name and address info.
Both tables have more than 14 million records, when we execute the procedure with 1000 unique records passed in filters list it took around 7 minutes to return the result (1400 records).
Filter criteria is: contains(name) and streetaddress, city, state, zip exact match.
Is there any alternate to avoid while loop as SQL Server CONTAINS function required string value or variable?
CREATE TABLE [dbo].[Names]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[UIN] [varchar](9) NULL,
[SNAME] [varchar](500) NULL,
CONSTRAINT [PK_Names]
PRIMARY KEY CLUSTERED ([ID] ASC)
)
CREATE TABLE [dbo].[ADDRESSES]
(
[UIN] [varchar](9) NULL,
[STREET1] [varchar](100) NULL,
[STREET2] [varchar](50) NULL,
[CITY] [varchar](30) NULL,
[STATE] [varchar](2) NULL,
[ZIP] [varchar](10) NULL
) ON [PRIMARY]
CREATE TYPE [dbo].[SearchFilter] AS TABLE
(
[UIN] [varchar](40) NULL,
[SNAME] [varchar](max) NULL,
[StreetAddress] [varchar](max) NULL,
[City] [varchar](max) NULL,
[State] [varchar](50) NULL,
[Zip] [varchar](20) NULL
)
-- Stored procedure logic
DECLARE #filterList AS [dbo].[SearchFilter]
DECLARE #NoOfRows INT, #counter INT = 0
SET #NoOfRows = (SELECT COUNT(1) FROM #filterList)
DECLARE #result TABLE (UIN varchar(40),
NAME varchar(500),
StreetAddress varchar(1000),
Zipcode varchar(20),
State varchar(20),
City varchar(1000),
IsRecordFound varchar(50)
);
WHILE (#NoOfRows > #counter)
BEGIN
DECLARE #SearchName VARCHAR(4000)
SET #SearchName = (SELECT '"'+SNAME+'"' FROM #filterList ORDER BY SNAME OFFSET #counter ROWS FETCH NEXT 1 ROWS ONLY)
--Start: Process to Select Records
;WITH Filter_CTE AS
(
SELECT
SNAME, StreetAddress, City, State, ZipCode
FROM
#filterList
ORDER BY
SNAME
OFFSET #counter ROWS FETCH NEXT 1 ROWS ONLY
)
INSERT INTO #result (UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE, IsRecordFound)
SELECT DISTINCT
en.UIN, ISNULL(en.SNAME, Filter_CTE.SNAME),
Filter_CTE.StreetAddress, Filter_CTE.ZipCode,
Filter_CTE.state, Filter_CTE.City,
IIF(en.UIN IS NULL, 'Not Found', 'Found') AS IsRecordFound
FROM
dbo.Names en
INNER JOIN
dbo.ADDRESSES ea ON en.UIN = ea.UIN
RIGHT JOIN
Filter_CTE ON ea.ZIP = Filter_CTE.Zip
AND ea.STATE = Filter_CTE.State
AND ea.CITY = Filter_CTE.City
AND (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')) = Filter_CTE.StreetAddress
AND CONTAINS(en.SNAME,#SearchName)
--END
SET #counter += 1
END
SELECT
UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE
FROM
#result
Currently it is not possible to use column names as search condition in CONTAINS or CONTAINSTABLE. So, you cannot do direct JOIN between data table and the SearchFilter table with FTS predicates applied.
The current solution found in other questions/forums is to loop through the filters list and feed CONTAINS with search condition in a variable, just as you do. So, you won't get rid of this loop.
However, looking at your query I see a number of other problems which may affect performance:
DISTINCT clause in INSERT INTO #result ... SELECT DISTINCT .... It's on the level where you JOIN to tables with millions of records. Though I understand that final result may contain only a few thousands of rows, it's better to move DISTINCT to this line:
SELECT DISTINCT
UIN, NAME, STREETADDRESS, CITY, STATE, ZIPCODE, PHONE
FROM
#result
This condition AND (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')) = Filter_CTE.StreetAddress is certainly NOT SARGable. You use concatenation and function (ISNULL()) which prevents SQL Server from using existing indexes over dbo.ADDRESSES ea table. Check this question: What makes a SQL statement sargable? to see how to construct JOIN / WHERE conditions in such a way that will allow the use of indexes.
In this particular case it's better to add a computed column to the dbo.Addresses table and then build an index over it (or add it to the existing index):
CREATE TABLE [dbo].[ADDRESSES]
(
...
STREET as (ISNULL(ea.STREET1, '') + ' ' + ISNULL(ea.STREET2, '')),
...
)
So fix the above 1. and 2. then comment the AND CONTAINS(en.SNAME,#SearchName) condition in RIGHT JOIN and notice execution time. Afterwards, uncomment the CONTAINS condition and see how much delay was added. This way you will know for sure if it's FTS engine to blame for the delay or your main query itself needs improvements.
To be able to advise more, we need to see the execution plans for your procedure. You can share your query execution plan using this page: https://www.brentozar.com/pastetheplan/ .
HTH

Insert data from user-defined table on some fields, other fields must use scalar variable

How would I make use of my user-defined table that comes loaded with data, insert into a table but 1 of the table fields won't be using the data from the User Defined Table. I want a scalar variable to take its place.
#dataTableType is the following user-defined table:
CREATE TYPE [dbo].[NewSequenceType] AS TABLE (
[FK_Sequence] [int] NULL,
[FK_Status] [int] NULL,
[FK_Shift] [int] NULL,
[PK_SequenceType] [int] NULL,
[TypeName] [varchar](30) NULL,
[SequenceName] [varchar](100) NULL,
[SequenceDetails] [varchar](400) NULL,
[SequenceStatus] [varchar](15) NULL,
[SequenceShift] [varchar](15) NULL,
[EmployeeId] [varchar](8) NULL,
[EquipmentId] [varchar](25) NULL,
[Comments] [varchar](512) NULL,
[EnteredDate] [datetime] NULL
)
My stored procedure:
ALTER PROCEDURE [dbo].[spNewInspectionEntry] (#dataTableType NewSequenceType READONLY)
INSERT INTO dbo.PIT_Inspection (FK_Sequence, FK_Status, FK_Shift, FK_EmployeeName, FK_EquipmentName, Comments, EnteredDate)
SELECT
FK_Sequence, FK_Status, FK_Shift, EmployeeId,
EquipmentId, Comments, EnteredDate
FROM
#dataTableType;
What I'm looking to do:
DECLARE #EmployeeIDExists varchar(8);
--Note that I only care about one row, this is Ok.
SELECT TOP 1 #EmployeeIDExists = EmployeeId FROM #dataTableType;
--Retrieve PKEmployeeId
SELECT #EmployeeIdPK = PK_EmployeeName
FROM dbo.PIT_EmployeeName
WHERE EmployeeId = #EmployeeIDExists
--Now I need to insert the value of #EmployeeIdPK? Along with the rest, it needs to replace EmployeeID and EquipmentId, Not sure how to...
INSERT INTO dbo.PIT_Inspection (FK_Sequence, FK_Status, FK_Shift, FK_EmployeeName, FK_EquipmentName, Comments, EnteredDate)
SELECT
FK_Sequence, FK_Status, FK_Shift, EmployeeId,
EquipmentId, Comments, EnteredDate
FROM
#dataTableType;
How can I get #EmployeeIdPK in Along with the rest, it needs to replace EmployeeID, I don't want the EmployeeId from the user-defined table to go there, I want the variable #EmployeeIdPK instead.
You can put any expression, variable, and literal value in the SELECT list. Just keep in mind that those values will be repeated for all rows.
Meaning:
SELECT Field1,
Field2,
'hello' AS [LiteralText],
5 AS [LiteralNumber],
#Variable AS [ValueFromVariable]
FROM TableName;
will repeated those literal and variable values for all rows.
Hence:
INSERT INTO dbo.PIT_Inspection (FK_Sequence, FK_Status, FK_Shift, FK_EmployeeName,
FK_EquipmentName, Comments, EnteredDate)
SELECT
FK_Sequence, FK_Status, FK_Shift, #EmployeeIdPK,
EquipmentId, Comments, EnteredDate
FROM
#dataTableType;

SQL loop executes but new old values are over written

As my question title says, my program loops but all of my values I updated are being overwritten. Here's the code posted below. Say minRownum is 1 and max is 12, I see the loop execute 12 times correctly and min gets updated +1 each time. But in the end result, only the final row in my column whose RowNum is 12 have any values
I'm not exactly sure why overwriting is occurring since I'm saying "Update it where the rownumber = minrownumber" then I increment minrownum.
Can anyone point to what I am doing wrong? Thanks
WHILE (#MinRownum <= #MaxRownum)
BEGIN
print ' here'
UPDATE #usp_sec
set amount=(
SELECT sum(amount) as amount
FROM dbo.coverage
inner join dbo.owner
on coverage.api=owner.api
where RowNum=#MinRownum
);
SET #MinRownum = #MinRownum + 1
END
PS: I edited this line to say (below) and now every value has the same wrong number (its not distinct but duplicated to all.
set amount = (SELECT sum(amount) as amount
FROM dbo.coverage
INNER JOIN dbo.owner ON coverage.api = owner.api
where RowNum=#MinRownum
) WHERE RowNum = #MinRownum;
Tables:
CREATE TABLE dbo. #usp_sec
(
RowNum int,
amount numeric(20,2),
discount numeric(3,2)
)
CREATE TABLE [dbo].[handler](
[recordid] [int] IDENTITY(1,1) NOT NULL,
[covid] [varchar](25) NULL,
[ownerid] [char](10) NULL
)
CREATE TABLE [dbo].[coverage](
[covid] [varchar](25) NULL,
[api] [char](12) NULL,
[owncovid] [numeric](12, 0) NULL,
[amount] [numeric](14, 2) NULL,
[knote] [char](10) NULL
)
CREATE TABLE [dbo].[owner](
[api] [char](12) NOT NULL,
[owncovid] [numeric](12, 0) NULL,
[ownerid] [char](10) NOT NULL,
[officer] [char](20) NOT NULL,
[appldate] [date] NOT NULL
)
Your UPDATE statement needs its own WHERE clause. Otherwise, each UPDATE will update every row in the table.
And the way you have this written, your subquery still needs its WHERE clause too. In fact, you need to definitively correlate the subquery to your table's (#usp_sec) rows. We cannot tell you how that should be done without more information such as your table definitions.

How to increment a primary key in an insert statement in SQL Server 2005

I need to write an insert statement into a table the columns looks like this
demandtypeid (PK, FK, int, not null)
characvalueid (PK, FK, int, not null)
percentage (int null)
lastuser (varchar(100), null)
lastedited (datetime, null)
Here is the INSERT statement. Notice the there is not values at the
value( , , 'Bob')
as I think that's where the auto-increment command should go
insert into tr_demandtypecharac(demandtypeID, characvalueid, lastuser)
values( , , 'Bob')
Please help with a simple little statement
I just want to know how to manually insert into this table
Here's my table structure:
CREATE TABLE [dbo].[tr_demandtypecharac](
[demandtypeid] [int] NOT NULL,
[characvalueid] [int] NOT NULL,
[percentage] [int] NULL,
[lastuser] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[lastedited] [datetime] NULL,
CONSTRAINT [PK_tr_dtc_pkey] PRIMARY KEY CLUSTERED
(
[demandtypeid] ASC,
[characvalueid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[tr_demandtypecharac] WITH CHECK
ADD CONSTRAINT [FK_tr_dtc_cvid]
FOREIGN KEY([characvalueid]) REFERENCES [dbo].[tr_characvalue] ([characvalueid])
ALTER TABLE [dbo].[tr_demandtypecharac] WITH CHECK
ADD CONSTRAINT [FK_tr_dtc_dtid]
FOREIGN KEY([demandtypeid]) REFERENCES [dbo].[tr_demandtype] ([demandtypeid])
If you want an int column that is unique and autoincrementing, use the IDENTITY keyword:
CREATE TABLE new_employees
(
id_num int IDENTITY(1,1),
fname varchar (20),
minit char(1),
lname varchar(30)
)
Then when you insert into the table, do not insert anything for that column -- it will autoincrement itself.
Given the CREATE TABLE statement you posted, without auto-increment (aka identity) columns, you would insert providing all columns and values, like this:
insert into tr_demandtypecharac(
demandtypeid, characvalueid,
percentage, lastuser, lastedited)
values(2, 3, 80, 'Bob', '01/01/2012')
If, however, you do make them auto-increment by changing the CREATE TABLE to:
CREATE TABLE [dbo].[tr_demandtypecharac](
[demandtypeid] [int] NOT NULL IDENTITY(1,1),
[characvalueid] [int] NOT NULL IDENTITY(1,1),
[percentage] [int] NULL,
[lastuser] [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[lastedited] [datetime] NULL,
CONSTRAINT [PK_tr_dtc_pkey] PRIMARY KEY CLUSTERED
(
[demandtypeid] ASC,
[characvalueid] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
)
Then you would insert providing all non-identity (non-autoincrement) columns like this:
insert into tr_demandtypecharac(
percentage, lastuser,
lastedited)
values(80, 'Bob', '01/01/2012')
However, it is not common to have more than one column as an identity (autoincrement) column, and generally, this column is the only PRIMARY KEY column.
If a column is an autoincement column (which is different than a primary key column) then you omit the column in your insert statement and it will be filled in.
INSERT INTO tr_demandtypecharac (lastuser) VALUES ('Bob')
I had a similar issue and needed to update a purchased database with a set of records. My solution was to find the highest key used so far, then use that as the base of my insert. The core of it was ROWNUMBER() OVER(ORDER BY PART_CODE).
The key is the "recnum" field in the inadjinf table. I determined that the highest current key was 675400 and updated my query to be:
insert into inadjinf (recnum, user_id, adj_type, adj_status, trans_date, part_code, lotqty, uom, cost_ctr, lot, location, to_cost_ctr, to_location, rec_status, to_part_grade, to_rec_status, remarks1, uom_conv)
select ROW_NUMBER() OVER(ORDER BY INVDET.PART_CODE) + 675400 as recnum, 'CHRSTR' as user_id, 'M' as adj_type, 'O' as adj_status, '2020-10-23' as trans_date, invdet.part_code, sum(lotqty) as lotqty, uom,
cost_ctr, lot, location, 'NS' as to_cost_ctr, '500A' as to_location, rec_status, 'Q' as to_part_grade, 'H' as to_rec_status, 'NS Scrap Request from MSobers 10/21/2020' as remarks1, '1' as uom_conv
from invdet
inner join partmstr on invdet.part_code = partmstr.part_code
where
invdet.part_code In
(
'86038',
'1271',
'VM-0021',
'CO-0107',
...
'FO-0391',
'FO-0376'
)
and lot not in (select lot from inadjinf where trans_date = '2020-10-23' and user_id = 'CHRSTR')
group by invdet.part_code, uom, cost_ctr, lot, location, rec_status
My output started with 675401 and went up from there. In the end, I updated the system's internal "next id field" table record.
You should not use int as primary keys... heres a article about it: http://techtrainedmonkey.com/2012/07/30/why-integers-are-lousy-primary-keys/
but if you do... set the field as identity and Sql Server will do it for you... check it out: http://msdn.microsoft.com/en-us/library/ms186775.aspx

Subquery Performance - Non Unique Column in Where Clause

I have two tables
Table Jobs
[ID] [int] IDENTITY(1,1) NOT NULL,
[title] [varchar](150) NULL,
[description] [text] NULL
Table JobSkills
[id] [int] IDENTITY(1,1) NOT NULL,
[jobId] [int] NULL,
[skill] [varchar](150) NULL
Shown above partial list of columns.
For table JobSkills I have indexed jobId column, column skill is full text indexed.
I have a stored procedure to get the list of jobs. sort of like this.
Select totalItems
,Id,title
from
(
Select Row_Number() over(Order By
CASE WHEN #sortBy Is Not Null AND #sortBy='relevance'
THEN
SkillMatchRank
END DESC
,CASE WHEN #sortBy Is Not Null AND #sortBy='date' THEN CreateDate END DESC
) As rowNumber
,COUNT(*) OVER() as totalItems
,ID,createDate,title
from Jobs J
OUTER APPLY dbo.GetJobSkillMatchRank(J.ID,#searchKey) As SkillMatchRank
Where
--where conditions here
) tempData
where
rowNumber>=CASE WHEN #startIndex>0 AND #endIndex>0 THEN #startIndex ELSE rowNumber END
AND rowNumber<=CASE WHEN #startIndex>0 AND #endIndex>0 THEN #endIndex ELSE rowNumber END
I have created a inline table valued function to get the skill matching rank.
CREATE FUNCTION [dbo].[GetJobSkillMatchRank]
(
#jobId int,
#searchKey varchar(150)
)
RETURNS TABLE
AS
RETURN
(
select SUM(ISNULL(JS2.[Rank],0)) as rank
from FREETEXTTABLE(JobSkills,skill,#searchKey) JS2
Where JS2.[Key] in (Select ID from JobSkills Where jobId=#jobId)
)
GO
Problem
Query runs super slow, more then a minute.
My observation
For the table valued function if I set jobId=1 (I do have a job with id=1) then it performs super fast as desired.
I understand that jobId is not unique column on JobSkills table.
In this case how could I improve the performance???
UDFs are great in certain cases, but the execution plans don't get cached like sprocs do. If you try using another derived table instead of a function, the query might perform better.