I am trying to write a procedure that will check all rows in my table and if itemID = 'CC100' then I need to insert a new row into the table. I have generated this script, but I am getting an error when I try to execute it
Msg 156, Level 15, State 1, Line 33
Incorrect syntax near the keyword 'Select'.
How should this be altered to become valid t-sql, or what is a more appropriate way to accomplish my desired result? Sample DDL is below:
--Create Holding Table
Declare Table #Items
(
itemID varchar(20)
,itemName varchar(100)
,qty int
,storeID int
)
--Insert Some Sample Data
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CZ100', 'Coke Zero', 4, 123), ('CZ100', 'Coke Zero', 3, 201)
,('CZ200', 'Cherry Coke Zero', 4, 311), ('CC100', 'Coca-Cola', 6, 400)
,('CC100', 'Coca-COla', 8, 500)
--Select data that needs to be split into secondary table
Select storeID, Qty Into #NeedExtra from #Items WHERE itemID = 'CC100'
--Declare variables
Declare #storeID int, #Qty int
--Create Cursor
DECLARE cursor1 CURSOR FOR
--Select statement to insert into variables
SELECT
storeID, qty
FROM #NeedExtra
OPEN cursor1
--Iterate cursor
FETCH NEXT FROM cursor1 INTO #storeID, #qty
--Continue as long as cursor is not empty
WHILE ##FETCH_STATUS = 0
BEGIN
--Insert Values
Insert Into #Items (itemID, itemName, qty, storeID) Values
Select #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
--Grab next item from temp table
FETCH NEXT FROM cursor1 INTO #storeID, #qty
END
--Close cursor
CLOSE cursor1
--Deallocate cursor
DEALLOCATE cursor1
--Select statements
Select * FROM #NeedExtra
SELECT * FROM #Items
First, your insert query in while loop is not correct.
Insert Into #Items (itemID, itemName, qty, storeID) Values
Select #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
There isn't a syntax like Insert into ... values select, and number of columns inserted is not matched.
And if it's correct the item with value #storeID, 'CC200', 'Coca-Cola Syrup', #Qty, #storeID will be duplicate many times equals count of #NeedExtra.
The correct query would be
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CC200', 'Coca-Cola Syrup', #Qty, #storeID)
Second, you should avoid using CURSOR and change your CURSOR loop by this insert query.
Insert Into #Items (itemID, itemName, qty, storeID)
Select 'CC200', 'Coca-Cola Syrup', t.Qty, t.storeID
FROM #Items t WHERE t.itemID = 'CC100'
The right syntax of INSERT INTO SELECT doesn't use values keyword. So just remove Values keyword from line 33 of your procedure.
I altered your code a follows, should work now.
--Create Holding Table
Declare #Items As Table
(
itemID varchar(20)
,itemName varchar(100)
,qty int
,storeID int
)
--Insert Some Sample Data
Insert Into #Items (itemID, itemName, qty, storeID) Values
('CZ100', 'Coke Zero', 4, 123), ('CZ100', 'Coke Zero', 3, 201)
,('CZ200', 'Cherry Coke Zero', 4, 311), ('CC100', 'Coca-Cola', 6, 400)
,('CC100', 'Coca-COla', 8, 500)
--Select data that needs to be split into secondary table
Select storeID, Qty Into #NeedExtra from #Items WHERE itemID = 'CC100'
--Declare variables
Declare #storeID int, #Qty int
--Create Cursor
DECLARE cursor1 CURSOR FOR
--Select statement to insert into variables
SELECT
storeID, qty
FROM #NeedExtra
OPEN cursor1
--Iterate cursor
FETCH NEXT FROM cursor1 INTO #storeID, #qty
--Continue as long as cursor is not empty
WHILE ##FETCH_STATUS = 0
BEGIN
--Insert Values
Insert Into #Items (itemID, itemName, qty, storeID)
Select 'CC200', 'Coca-Cola Syrup', #Qty, #storeID FROM #NeedExtra
--Grab next item from temp table
FETCH NEXT FROM cursor1 INTO #storeID, #qty
END
--Close cursor
CLOSE cursor1
--Deallocate cursor
DEALLOCATE cursor1
--Select statements
Select * FROM #NeedExtra
SELECT * FROM #Items
Related
I have the following trigger:
ALTER TRIGGER .[dbo].[trgAfterInsertComment]
ON .[dbo].[Comment]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #Id int;
declare #LoanId int;
declare #CopyId int;
declare #CustomerId int;
declare #Comment nvarchar(255);
--DECLARE cur CURSOR FOR
select #Id = Id from inserted
select #LoanId = LoanId from inserted
--select #CopyId = CopyId from deleted
--select #CustomerId = CustomerId from deleted
select #Comment = Comment from inserted
-- OPEN cur
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--WHILE ##FETCH_STATUS = 0 BEGIN
-- your business logic
Declare #Title nvarchar(255);
select #Title = (Select Title from Book where ISBN = (select ISBN from copy where Id = (select CopyId from Loan where Id = #LoanId)))
select #CustomerId = (Select CustomerId from Loan where Id = #LoanId)
select #CopyId = (Select CopyId from Loan where Id = #LoanId)
insert into Activity("Heading", "Date")
values(Concat('New Comment added - Id: ', #Id, ' Title: ', #Title, ' Copy Id: ', #CopyId, ' Customer Id: ', #CustomerId, ' Comment: ', #Comment), GETDATE())
--FETCH NEXT FROM cur INTO #Id, #ISBN, #Purchase_Date
--END
--CLOSE cur
--DEALLOCATE cur
end
As you can see I have commented out a cursor that I was using to handle multiple inserts. Could someone tell me how I can handle multiple inserts without the cursor, as after reading around I see that using a cursor is a bad idea?
With the above trigger, if I try to insert multiple lines like this:
USE [Library]
GO
INSERT INTO [dbo].[Comment]
([LoanId]
,[Comment])
VALUES
(47, 'test'),
(48, 'test'),
(50, 'test')
GO
Only the first row is inserted into my Activity table. Thanks for any help
You need to shift it to be set based, using variables and a loop will cause you issues. Can't test the below, but something like:
INSERT INTO Activity
(
Heading ,
[Date]
)
SELECT CONCAT('New Comment added - Id: ', I.id, ' Title: ', COALESCE(B.Title,''), ' Copy Id: ', COALESCE(L.CopyID,''), ' Customer Id: ', COALESCE(L.CustomerID,'')) ,
GETDATE()
FROM inserted AS I
LEFT JOIN Loan AS L ON I.loanId = L.loanId
LEFT JOIN Copy AS C ON C.Id = L.CopyId
LEFT JOIN Book AS B ON B.ISBN = C.ISBN;
Do this querying inserted table directly.
insert into [dbo].[Comment] (LoanId, Comment)
select LoanId, Comment from inserted
You can change the select query to more complex to achieve the result using query only.
I am new to Stored Procedures.I would like to have a cursor for selecting records from a table.If records is available insert into another.How to add a check for selected rows before insert.Thanks in advance.
Eg:
DECLARE cursor_name CURSOR FOR
SELECT Id From tbl WHERE where condition
OPEN cursor_name
FETCH NEXT FROM cursor_name INTO #id
WHILE ##FETCH_STATUS = 0
BEGIN
Insert statement
The variable ##FETCH_STATUS will return 0 only in case of success row is selected, based on your where condition. The code you provided in your question will be sufficient to take care of it. you can also refer below sample code. In this code i am inserting the row from table1 to table2 if the value of column1 is even and discarding odd rows -
-- CREATE Source table and add few records
create table #Table1
(
Col1 int,
col2 char(1)
)
insert into #Table1
select 1, 'A'
union all select 2, 'B'
union all select 3, 'C'
union all select 4, 'D'
union all select 5, 'E'
union all select 6, 'F'
union all select 7, 'G'
union all select 8, 'H'
--Create destination table
create table #Table2
(
Col1 int,
col2 char(1)
)
declare #Col1 int, #col2 char(1)
-- below cursor will insert only evern rows from surce table to destination
table
DECLARE Cur1 CURSOR FOR
SELECT Col1, col2
FROM #Table1
WHERE col1%2 = 0
OPEN Cur1
FETCH NEXT FROM Cur1 INTO #Col1 ,#col2
WHILE ##FETCH_STATUS = 0 -- this will return 0 only if a successful row is fatched
BEGIN
insert into #Table2
select #Col1 ,#col2
FETCH NEXT FROM Cur1 INTO #Col1 ,#col2
END
CLOSE Cur1
DEALLOCATE Cur1
I am facing scenario where i need to get the data from audit log table and show Old and new value.
For eg. Below is audit_Log table for Person
AUDIT_ID PERSON_ID OPERATION NAME ADDRESS AGE DOY
1 101 I Prashant Andheri 21 1991
2 101 U Prashant1 Santacruz 22 1990
3 101 U rashant2 Parle 23 1989
I want the latest value and previous value for all the columns as below,
PERSON_ID COLUMNS OLD_VALUE NEW_VALUE
101 OPERATION U U
101 NAME PRASHANT1 PRASHANT2
101 ADDRESS Santacruz Parle
101 AGE 22 23
101 BIRTH_YEAR 1990 1989
Can anyone please help me to get this result from above table.
Thanks,
Prashant
I try to find a function/ query to do what do you want but I do not found nothing. so I develop a procedure verify if work.
CREATE PROCEDURE _spManageAuditLog
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT AUDIT_ID, PERSON_ID, OPERATION, NAME, [ADDRESS], AGE, DOY, count(1)
FROM dbo.audit_Log
GROUP BY AUDIT_ID, PERSON_ID, OPERATION, NAME, [ADDRESS], AGE, DOY;
CREATE TABLE #row (personId Int, operation char(1), name nvarchar(250),[address] nvarchar(250), age smallint,
doy smallint);
CREATE TABLE #out (PersonID Int, [columnName] nvarchar(250), OLD_VALUE nvarchar(250),NEW_VALUE nvarchar(250));
--cursor variable
DECLARE
#AUDIT_ID int,
#PERSON_ID int,
#OPERATION char,
#NAME nvarchar,
#ADDRESS nvarchar,
#AGE smallint,
#DOY smallint;
DECLARE myCursor CURSOR FOR
SELECT AUDIT_ID, PERSON_ID, OPERATION, NAME, [ADDRESS], AGE, DOY
FROM dbo.audit_Log
OPEN myCursor
FETCH NEXT FROM myCursor INTO #AUDIT_ID, #PERSON_ID, #OPERATION, #NAME, #ADDRESS, #AGE, #DOY
WHILE ##FETCH_STATUS = 0
BEGIN
declare #countTempData int;
select #countTempData= count(1) from #row;
IF #countTempData=0
BEGIN
Insert into #row VALUES(#PERSON_ID, #OPERATION, #NAME, #ADDRESS, #AGE, #DOY);
--to debug
--SELECT * FROM #row;
END
ELSE
BEGIN
--do comparison previus row
INSERT INTO #out VALUES (#PERSON_ID, 'Operation', (SELECT TOP(1) OPERATION FROM #row) , #OPERATION );
INSERT INTO #out VALUES (#PERSON_ID, 'Name',(SELECT TOP(1) NAME FROM #row), #NAME );
INSERT INTO #out VALUES (#PERSON_ID, 'Address',(SELECT TOP(1) ADDRESS FROM #row), #ADDRESS );
INSERT INTO #out VALUES (#PERSON_ID, 'Age',(SELECT TOP(1) AGE FROM #row), #AGE );
INSERT INTO #out VALUES (#PERSON_ID, 'BirthYear',(SELECT TOP(1) DOY FROM #row), #DOY );
--new item became temp item
TRUNCATE TABLE #row
INSERT INTO #row VALUES(#PERSON_ID, #OPERATION, #NAME, #ADDRESS, #AGE, #DOY);
--to debug
--SELECT * FROM #row;
END
-- Get the next.
FETCH NEXT FROM myCursor INTO #AUDIT_ID, #PERSON_ID, #OPERATION, #NAME, #ADDRESS, #AGE, #DOY
END
CLOSE myCursor;
DEALLOCATE myCursor;
SELECT * FROM #out;
END
GO
SELECT PERSON_ID, [COLUMNS], OLD_VALUE, NEW_VALUE
FROM(
SELECT TOP 2 PERSON_ID, ( CASE ( ROW_NUMBER() OVER( ORDER BY AUDIT_ID DESC )) WHEN 1 THEN 'NEW_VALUE' ELSE 'OLD_VALUE' END ) AS [Version],
CAST( OPERATION AS VARCHAR( 100 )) AS OPERATION, CAST( NAME AS VARCHAR( 100 )) AS NAME,
CAST( ADDRESS AS VARCHAR( 100 )) AS ADDRESS, CAST( AGE AS VARCHAR( 100 )) AS AGE, CAST( DOY AS VARCHAR( 100 )) AS DOY
FROM audit_Log
WHERE PERSON_ID = 101
ORDER BY AUDIT_ID DESC ) AS SourceData
UNPIVOT(
COL_VALUE FOR [COLUMNS] IN( NAME, ADDRESS, OPERATION, AGE, DOY )
) AS UnpivotColumns
PIVOT(
MIN( COL_VALUE ) FOR [Version] IN( [NEW_VALUE], [OLD_VALUE] )
) AS PivotOldNew
Notes:
You need to convert all of your audit column values to a common type. I
chose VARCHAR( 100 ) but you may need to choose something else.
This code also works when only one audit record exists. In this case it
will show NULL for OLD_VALUES
References:
http://mangalpardeshi.blogspot.com.au/2009/04/unpivot-multiple-columns.html
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot
EDIT: excluded erroneous code at the end of the query
I have comma separated column which represents the ids of cities like:
ID | Name
1 | 1,2,3
2 | 2,3,4
I want to make query to get name of the this value field. There is City Table which has two columns: id and name of cities
EXPECTED OUTPUT
ID | VALUES
1 | mumbai,delhi,pune
2 | delhi,pune,chennai
I can make a query if there is only one id in a column like:
select data.id,city.name from data,city where data.values=city.cityid
but I am not getting how to retrieve the data if there are multiple comma-separated values in one field.
The easy way is to convert CSV values to rows for each Id, join that with CITY table and convert back to CSV values. I have written the logic inside the query.
;WITH CTE1 AS
(
-- Convert CSV to rows
SELECT Id,LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'NAME'
FROM
(
-- To change ',' to any other delimeter, just change ',' before '</M><M>' to your desired one
SELECT Id,CAST ('<M>' + REPLACE(Name, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM #TEMP
) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)
)
,CTE2 AS
(
-- Now join the values in rows with Id in CITY table
SELECT T.ID,T.NAME,C.CITYNAME
FROM CTE1 T
JOIN #CITY C ON T.NAME=C.ID
)
-- Now convert back to CSV format
SELECT DISTINCT ID,
SUBSTRING(
(SELECT ', ' + CITYNAME
FROM CTE2 I
WHERE I.Id=O.Id
FOR XML PATH('')),2,200000) [VALUES]
FROM CTE2 O
Click here to view result
to do this please do following sections:
1-Create Function to get table of comma separate value in each row
CREATE FUNCTION [dbo].[fn_Split](
#ForigenKey INT,
#String NVARCHAR (4000),
#Delimiter NVARCHAR(10)
)
RETURNS #ValueTable TABLE ([ID] INT IDENTITY NOT NULL,FID int null,[Value] NVARCHAR(4000))
BEGIN
DECLARE #NextString NVARCHAR(4000)
DECLARE #Pos INT
DECLARE #NextPos INT
DECLARE #CommaCheck NVARCHAR(1)
--Initialize
SET #NextString = ''
SET #CommaCheck = RIGHT(#String,1)
--Check for trailing Comma, if not exists, INSERT
--if (#CommaCheck <> #Delimiter )
SET #String = #String + #Delimiter
--Get position of first Comma
SET #Pos = CHARINDEX(#Delimiter,#String)
SET #NextPos = LEN(#Delimiter)
--Loop while there is still a comma in the String of levels
WHILE (#pos <> 0)
BEGIN
SET #NextString = SUBSTRING(#String, 1, #Pos - 1)
INSERT INTO #ValueTable ( FID,[Value]) VALUES (#ForigenKey ,#NextString)
SET #String = SUBSTRING(#String,#pos + LEN(#Delimiter),LEN(#String))
SET #NextPos = #Pos
SET #pos = CHARINDEX(#Delimiter,#String)
END
RETURN
END
GO
2- create Concat Aggregate with the folwing link
Concat Aggregate
3- you can get your data with below select
DECLARE #ID INT,#Name NVARCHAR(4000)
DECLARE #ValueTable table ([ID] int NOT NULL,[Value] INT)
DECLARE mycur CURSOR FOR
SELECT TOP(1000) ID,Name FROM TableA
OPEN mycur
FETCH NEXT FROM mycur INTO #ID,#Name
WHILE(##FETCH_STATUS=0)
BEGIN
INSERT INTO #ValueTable
( ID, Value )
SELECT #ID,Value FROM dbo.fn_Split(#Name,',')
FETCH NEXT FROM mycur INTO #ID,#Name
END
CLOSE mycur
DEALLOCATE mycur
SELECT * FROM #ValueTable
SELECT ID,dbo.ConcatAggregate(CityName) FROM #ValueTable
inner join city on value=cityid GROUP BY ID
Is there an easy way of determining the most frequently occuring word in a column/field using T-SQL or VBA?
I am working on a fuzzy matching system for two given recordsets and would like to produce a matching string where the most frequently occuring words are removed. As the data is from a customer relations management database terms like "limited", "ltd", "plc" and "CORPORATION" would be removed.
Written for sql-server 2005+
Function to split:
create function f_split
(
#a varchar(max),
#delimiter varchar(20)
)
RETURNS #t TABLE(substr varchar(200))
as
begin
set #a = #a + #delimiter
;with a as
(
select cast(1 as bigint) f1, charindex(#delimiter, #a) f2
where len(#a) > 0
union all
select f2 + (len(#delimiter)) + 1, charindex(#delimiter, #a, f2+1)
from a
where f2 > 0
)
insert #t
select substring(#a, f1, f2 - f1) from a
where f1 < f2
return
end
go
Query:
--testdata
declare #table table(name varchar(50))
insert #table values('bla bla bla ltd')
insert #table values('bla plc ltd')
insert #table values('more text CORPORATION')
declare #matchlist table(name varchar(50), replacement varchar(50))
insert #matchlist values('ltd', 'limited')
insert #matchlist values('plc', 'limited')
insert #matchlist values('CORPORATION', 'limited')
--query
select coalesce(m.replacement, a.substr) name, count(*) count from #table p
cross apply
(
select substr from
dbo.f_split(p.name, ' ')
) a
left join
#matchlist m
on a.substr = m.name
group by coalesce(m.replacement, a.substr)
order by 2 desc
Result:
name count
---- -----
bla 4
limited 4
more 1
text 1
Hope this will be useful to you.
create table sometable
( id integer not null primary key identity
, mYWords text not null
);
insert into sometable (mYWords)
values ('a word that appears maximum number of times in a column')
insert into sometable (mYWords)
values ('Is it possible to get words from text columns in a sql server database')
insert into sometable (mYWords)
values ('This could solve my problem if reffered column contain only single word')
insert into sometable (mYWords)
values ('that''s going to require that you split out every word in the column individually')
insert into sometable (mYWords)
values ('the query will definitely not be easy to write')
insert into sometable (mYWords)
values ('Please read the sticky at the top of the board')
insert into sometable (mYWords)
values ('The physical order of data in a database has no meaning')
GO
CREATE TABLE WordList (
Word varchar(256)
, WordId int IDENTITY(1,1)
, Add_Dt datetime DEFAULT (GetDate()))
GO
CREATE UNIQUE INDEX UnqueWords_PK ON WordList(Word)
GO
CREATE PROC isp_INS_WORD_LIST
AS
BEGIN
SET NOCOUNT ON
DECLARE #Words INT, #Pos INT, #x Int, #str varchar(256)
, #word varchar(256), #start int, #end int, #exitstart int
SELECT #Words = 0, #Pos = 1, #x = -1, #Word = '', #start = 1
DECLARE Cur1 CURSOR FOR SELECT mYWords FROM sometable
OPEN Cur1
FETCH NEXT FROM Cur1 INTO #str
WHILE ##FETCH_STATUS = 0
BEGIN
WHILE (#x <> 0)
BEGIN
SET #x = CHARINDEX(' ', #str, #Pos)
IF #x <> 0
BEGIN
SET #end = #x - #start
SET #word = SUBSTRING(#str,#start,#end)
IF NOT EXISTS (SELECT * FROM WordList WHERE Word = #Word)
INSERT INTO WordList(Word) SELECT #word
-- SELECT #Word, ##ROWCOUNT,##ERROR
-- SELECT #x, #Word, #start, #end, #str
SET #exitstart = #start + #end + 1
SET #Pos = #x + 1
SET #start = #x + 1
SET #Words = #Words + 1
END
IF #x = 0
BEGIN
SET #word = SUBSTRING(#str,#exitstart,LEN(#str)-#exitstart+1)
IF NOT EXISTS (SELECT * FROM WordList WHERE Word = #Word)
INSERT INTO WordList(Word) SELECT #word
-- SELECT #Word, ##ROWCOUNT,##ERROR
-- SELECT #x, #Word, #exitstart, LEN(#str)-#exitstart, #str
END
END
FETCH NEXT FROM Cur1 INTO #str
SELECT #Words = 0, #Pos = 1, #x = -1, #Word = '', #start = 1
END
CLOSE Cur1
DEALLOCATE Cur1
SET NOCOUNT OFF
RETURN #Words
END
GO
EXEC isp_INS_WORD_LIST
GO
SELECT * FROM WordList ORDER BY Word
GO
DROP PROC isp_INS_WORD_LIST
DROP TABLE WordList, sometable
GO