I'm trying to write a SQL query that accepts two inputs (a content ID and a content type), populates a temp table from different source tables depending on what the user sets as content type, and then finally runs a query against the temp table. I think I'm getting stuck on incorporating my temp table into my IF/ELSE statements.
So my question is, why does this return some non-zero number of results:
DECLARE #contentID int, #contenttype varchar
SET #contentid = 28861
SET #contenttype = 'resource'
DECLARE #tags_current TABLE (contentID int, taxonomyID int, isPrimary int)
INSERT INTO #tags_current (contentID, taxonomyID, isPrimary)
SELECT resourceID as contentID, taxonomyID, isPrimary
FROM resource2taxonomy r2t
WHERE r2t.resourceID = #contentID
SELECT * FROM #tags_current
Whereas this returns zero results:
DECLARE #contentID int, #contenttype varchar
SET #contentid = 28861
SET #contenttype = 'resource'
DECLARE #tags_current TABLE (contentID int, taxonomyID int, isPrimary int)
IF (#contenttype = 'resource')
BEGIN
INSERT INTO #tags_current (contentID, taxonomyID, isPrimary)
SELECT resourceID as contentID, taxonomyID, isPrimary
FROM resource2taxonomy r2t
WHERE r2t.resourceID = #contentID
END
SELECT * FROM #tags_current
Also, I've tried this, and it also returns zero results:
DECLARE #contentID int, #contenttype varchar, #command varchar
SET #contentid = 28861
SET #contenttype = 'resource'
DECLARE #tags_current TABLE (contentID int, taxonomyID int, isPrimary int)
IF (#contenttype = 'resource')
BEGIN
SET #command = 'INTO #tags_current (contentID, taxonomyID, isPrimary) SELECT resourceID as contentID, taxonomyID, isPrimary FROM resource2taxonomy r2t WHERE r2t.resourceID = #contentID'
END
EXECUTE(#command)
SELECT * FROM #tags_current
I've read up on this, this, and this, but for some reason it's just not clicking for me. I'm using MS SQL Server 2014, in case that helps. Here's the SQL Fiddle. Thanks!
This is actually very simple, you aren't giving a length to #contenttype, as such, by default it's taking a length of 1 char.
This will be clear if you do this:
DECLARE #contentID int, #contenttype varchar
SET #contentid = 28861
SET #contenttype = 'resource'
SELECT #contenttype
The result is r, so, IF (#contenttype = 'resource') is not true
Related
I am attempting to DECLARE a variable then SET it's value using a secondary variable which has already had it's value set.
I have tried:
DECLARE #Type VARCHAR = 'Some unique text';
DECLARE #TypeId UNIQUEIDENTIFIER;
SET #TypeId =
(
SELECT Id
FROM Types
WHERE Name = #Type
)
select #TypeId
To no avail. The result of the final SELECT statement is null. The following works:
DECLARE #TypeId UNIQUEIDENTIFIER;
SET #TypeId =
(
SELECT Id
FROM Types
WHERE Name = 'Some unique text'
)
select #TypeId
but I have several tables linked via dependencies and to delete an entry I need to traverse the tables in the correct order pulling the correct Ids. It is likely I will need to do this frequently so I want to reduce the leg work and just enter the text once and the script do the rest.
Is the syntax wrong or is this not possible?
DECLARE #Type VARCHAR = 'Some unique text';
It seems like you try to configure the variable value to be 'Some unique text' but since the type of the variable is VARCHAR(1) then when you set the value the server implicitly CONVERT it to VARCHAR(1) which lead to trunctaing the string and using only the first character
DECLARE #Type VARCHAR = 'Some unique text';
SELECT #Type
GO -- result is "S" and not "Some unique text"
To clarify, using DECLARE #Type VARCHAR without explicitly set the length is translated into 'DECLARE #Type VARCHAR(1)'
As a result of this issue, your comparing of the value probably result with no rows since you compare "S" and not "Some unique text". Your sub query is the same as SELECT Id FROM Types WHERE Name = 'S'
Here is a simple illustration of the issue
------------ DDL+DML: Creating sample table with some data
DROP TABLE IF EXISTS t1, t2
GO
CREATE TABLE t1 (
ID int, [Name] NVARCHAR(100)
)
GO
INSERT t1 (ID, [Name]) Values
(1, 'Mobile '),
(2, 'TV '),
(3, 'Display')
GO
----------- Using VARCHAR without length returns nothing
DECLARE #Type VARCHAR = 'Mobile';
SELECT #Type
DECLARE #TypeId INT;
SET #TypeId =
(
SELECT Id FROM t1 WHERE Name = #Type
)
select #TypeId
----------- Using VARCHAR(100) works great
DECLARE #Type VARCHAR(100) = 'Mobile';
SELECT #Type
DECLARE #TypeId INT;
SET #TypeId =
(
SELECT Id FROM t1 WHERE Name = #Type
)
select #TypeId
The function is seeking to return an integer value that is equal to the sum of the values that appear before zeros in the column and add it to the final value in the column.
CREATE FUNCTION name
(#p1 NVARCHAR(MAX),
#p2 INT,
#p3 INT)
RETURNS INT
AS
BEGIN
DECLARE #total INT = 0
DECLARE #cnt INT = 1;
DECLARE #row INT = 0
DECLARE #nextRow INT = 0;
DECLARE #tmp NVARCHAR(MAX)
SET #tmp = #p1
DECLARE #myTemp TABLE (Col INT, ID1 INT, ID2 INT, reading NVARCHAR(MAX));
DECLARE #zeroCols TABLE(rn INT, Col INT);
INSERT INTO #myTemp
SELECT ROW_NUMBER() OVER(ORDER BY nHeatID) Col, col2, col3, #tmp
FROM schema.table
WHERE col4 = #p2
AND col5 = #p3
SET #total = (SELECT TOP 1 #tmp FROM #myTemp ORDER BY col DESC)
INSERT INTO #zeroCols
SELECT ROW_NUMBER() OVER(ORDER BY col) rn, col
FROM #myTemp
WHERE #tmp = 0
WHILE #cnt <= (SELECT COUNT(Col) FROM #zeroCols)
BEGIN
SET #row = (SELECT Col FROM #zeroCols WHERE rn = #cnt)
IF ((SELECT #tmp FROM #myTemp WHERE col = #row-1) <> 0)
SET #total = #total + (SELECT #tmp FROM #myTemp WHERE col = #row-1);
SET #cnt = #cnt + 1;
END;
RETURN #total
END;
The #myTemp table place-holds data from my table with row numbers, the #zeroCols table holds the row numbers where the zeros are.
Then I loop over that set of values and decide if there is a nonzero value before the zero at the column provided and if there is, i add it to the total.
This worked before I tried to make it into a function.
Is it not liking the fact that I'm passing in a nvarchar as a column name?
And when I call it like so:
SELECT name('val', 0, 0)
I get this error:
Conversion failed when converting the nvarchar value 'val' to data type int
I've reduced the problem to the following:
#p1 nvarchar(max) -- Parameter of the function
--...
DECLARE #total INT = 0
DECLARE #tmp nvarchar(max)
SET #tmp = #p1
--...
DECLARE #myTemp TABLE(Col INT, ID1 INT, ID2 INT, reading nvarchar(max));
--...
SET #total = (SELECT TOP 1 #tmp FROM #myTemp ORDER BY col DESC) -- Can't convert property
You are assigning the value of #tmp (NVARCHAR(MAX)) to #total which is an INT.
I can't infer what you are trying to do with this, so I can't propose a fix, just make sure to assign data types that match.
I found that if I use a switch then I can decide a column name based on the param.
Can I pass column name as input parameter in SQL stored Procedure
This i my procedure,that determines classId and liveareaId for Animal to insert it into table
CREATE PROCEDURE insertAnimal
#name nvarchar,
#birthyear int,
#classname nvarchar,
#livearea nvarchar
AS
BEGIN
DECLARE #classid int
DECLARE #liveareaid int
SET #classid =
(SELECT Id
FROM dbo.Class
WHERE dbo.Class.Name = #classname)
SET #liveareaid =
(SELECT Id
FROM dbo.LiveArea
WHERE Name = #livearea)
INSERT INTO dbo.Animal (Name,BirthYear,ClassId,LiveAreaId) VALUES
(
#name,
#birthyear,
#classid,
#liveareaid
)
END
GO
I have a error:
Cannot insert the value NULL into column 'ClassId', table 'ZOO.dbo.Animal'; column does not allow nulls. INSERT fails.
Why ClassId is null, can you tell me why whis doesn't work.
SET #classid =
(SELECT Id
FROM dbo.Class
WHERE dbo.Class.Name=#classname)
This is because you have declared #classname as only nvarchar and have not specified a length. When length is not specified in a nvarchar variable declaration statement, the default length is 1.
Declare as:
CREATE PROCEDURE insertAnimal
#name nvarchar(10),
#birthyear int,
#classname nvarchar(10),
#livearea nvarchar(10)
...
CREATE PROCEDURE insertAnimal
#name nvarchar,
#birthyear int,
#classname nvarchar,
#livearea nvarchar
AS
BEGIN
DECLARE #classid int
DECLARE #liveareaid int
SET #classid =
(SELECT Id
FROM dbo.Class
WHERE dbo.Class.Name=#classname
AND dbo.Class.Id IS NOT NULL)
SET #liveareaid =
(SELECT Id
FROM dbo.LiveArea
WHERE Name=#livearea)
INSERT INTO dbo.Animal (Name,BirthYear,ClassId,LiveAreaId) VALUES
(
#name,
#birthyear,
#classid,
#liveareaid
)
END
GO
Can you tell us which parameteres are passing by you while calling procedure in your page/Query as well as sample data in your database?
It looks like data does not exists in your database according to your parameters in page.
Make sure #classname and #liveareaid data you are passing as a parameter, must be in database table dbo.Class and dbo.LiveArea respectively.
Try below queries first in SQL server.Does it giving any output by same parameters?
SELECT Id FROM dbo.Class WHERE dbo.Class.Name = #classname
SELECT Id FROM dbo.LiveArea WHERE Name = #livearea
I am using SQL Server 2008 R2. I am having some problems finding an effective coding pattern for SQL which supports code re-usability as well as flexibility. By re-usability, what I mean is keeping SQL queries in Stored Procedures and User Defined Functions.
Now, if I choose Stored Procedures, I will be sacrificing its usability in a query directly. If I choose User Defined Functions, I won't be able to use DML statements.
For example, suppose I created a Stored Procedures which inserts one contact record. Now, if I am having a table which can act as a source of multiple contact records, all I am left with are either WHILE loops or CURSORs, which is clearly not a recommended option, due to its performance drawbacks. And due to the fact that DML statements are not allowed in User Defined Functions, I simply cannot use them for this purpose.
Although, If I am not concerned with code re-usability, then instead of using Stored Procedures I can surely use same set of queries again and again to avoid while loops.
What pattern should I follow?
Here is a similar Stored Procedures:-
ALTER Proc [dbo].[InsertTranslationForCategory]
(
#str nvarchar(max),
#EventId int,
#CategoryName NVarchar(500),
#LanguageId int,
#DBCmdResponseCode Int Output,
#KeyIds nvarchar(max) Output
)as
BEGIN
DECLARE #XmlData XML
DECLARE #SystemCategoryId Int
DECLARE #CategoryId Int
Declare #Counter int=1
Declare #tempCount Int
Declare #IsExists int
Declare #TranslationToUpdate NVarchar(500)
Declare #EventName Varchar(200)
declare #Locale nvarchar(10)
declare #Code nvarchar(50)
declare #KeyName nvarchar(200)
declare #KeyValue nvarchar(500)
select #Locale=locale from languages where languageid = #LanguageId
SET #DBCmdResponseCode = 0
SET #KeyIds = ''
select #EventName = eventName from eventLanguages
where eventID = #EventId
--BEGIN TRY
Select #SystemCategoryId=CategoryId from SystemCategories where Name=rtrim(ltrim(#CategoryName))
Select #CategoryId=CategoryId from Categories where Name=rtrim(ltrim(#CategoryName)) and EventId=#EventId
if (#str='deactivate')
Begin
Delete from Codetranslation where CategoryId=#CategoryId
Update Categories set [Status]=0, Isfilter=0 where CategoryId=#CategoryId and Eventid=#EventId
Set #DBCmdResponseCode=2
return
End
set #XmlData=cast(#str as xml)
DECLARE #temp TABLE
(
Id int IDENTITY(1,1),
Code varchar(100),
Translation varchar(500),
CategoryId int
)
Insert into #temp (Code,Translation,CategoryId)
SELECT
tab.col.value('#Code', 'varchar(200)'),
tab.col.value('#Translation', 'varchar(500)'),#SystemCategoryId
FROM #XmlData.nodes('/Data') AS tab (col)
select #tempCount=Count(*) from #temp
if(IsNull(#CategoryId,0)>0)
Begin
While (#Counter <= #tempCount)
Begin
Select #IsExists= count(sc.categoryid) from #temp t Inner Join SystemCodetranslation sc
On sc.categoryid=t.CategoryId
where ltrim(rtrim(sc.code))=ltrim(rtrim(t.code)) and ltrim(rtrim(sc.ShortTranslation))=ltrim(rtrim(t.Translation))
and t.Id= #Counter
print #IsExists
Select #Code = Code , #KeyValue = Translation from #temp where id=#counter
set #KeyName = ltrim(rtrim(#EventName)) + '_' + ltrim(rtrim(#CategoryName)) + '_' + ltrim(rtrim(#Code)) + '_LT'
exec dbo.AddUpdateKeyValue #EventId,#Locale, #KeyName,#KeyValue,NULL,12
select #KeyIds = #KeyIds + convert(varchar(50),keyvalueId) + ',' from dbo.KeyValues
where eventid = #EventId and keyname = #KeyName and locale = #Locale
set #KeyName = ''
set #KeyValue = ''
Set #Counter= #Counter + 1
Set #IsExists=0
End
End
--- Inser data in Codetranslation table
if(isnull(#CategoryId,0)>0)
Begin
print #CategoryId
Delete from codetranslation where categoryid=#CategoryId
Insert into codetranslation (CategoryId,Code,LanguageId,ShortTranslation,LongTranslation,SortOrder)
SELECT
#CategoryId,
tab.col.value('#Code', 'varchar(200)'), #LanguageId,
tab.col.value('#Translation', 'varchar(500)'),
tab.col.value('#Translation', 'varchar(500)'),0
FROM #XmlData.nodes('/Data') AS tab (col)
Update Categories set [Status]=1 where CategoryId=#CategoryId and Eventid=#EventId
End
Set #DBCmdResponseCode=1
set #KeyIds = left(#KeyIds,len(#KeyIds)-1)
END
You can use table variable parameter for your user defined functions.
following code is an example of using table variable parameter in stored procedure.
CREATE TYPE IdList AS TABLE (Id INT)
CREATE PROCEDURE test
#Ids dbo.IdList READONLY
AS
Select *
From YourTable
Where YourTable.Id in (Select Id From #Ids)
End
GO
In order to execute your stored procedure use following format:
Declare #Ids dbo.IdList
Insert into #Ids(Id) values(1),(2),(3)
Execute dbo.test #Ids
Edit
In order to return Inserted Id, I don't use from Table Variable Parameter. I use following query sample for this purpose.
--CREATE TYPE NameList AS TABLE (Name NVarChar(100))
CREATE PROCEDURE test
#Names dbo.NameList READONLY
AS
Declare #T Table(Id Int)
Insert Into YourTable (Name)
OUTPUT Inserted.Id Into #T
Select Name
From #Names
Select * From #T
End
GO
I have a table that has two columns "name" and "ID". where ID is not null.
I am trying to create a stored prcedure to swap the IDs around for two names when imputed here is what i have so far.
CREATE PROCEDURE dbo.procName
#OldName NVARCHAR(128),
#NewName NVARCHAR(128)
AS
DECLARE #NewId0 INT,
#NewId1 INT,
#OldId0 INT,
#OldId1 INT,
#Number INT
SELECT #NewId0 = ID FROM Table1 WHERE [Name] = #NewName
SELECT #NewId1 = ID FROM Table1 WHERE [Name] = #NewName
SELECT #OldId0 = ID FROM Table1 WHERE [Name] = #OldName
SELECT #OldId1 = ID FROM Table1 WHERE [Name] = #OldName
SELECT #Number = 0
UPDATE Table1 SET ID = #Number WHERE ID = #NewId0
UPDATE Table1 SET ID = #NewId1 WHERE ID = #OldId0
UPDATE Table1 SET ID = #OldID1 WHERE ID = #NewID0
Go
All I get is the first name to have the value 0.
I think my logic is correct but it doesn't seem to be working is there something that I am missing?
Try something like
UPDATE Table1
SET ID = CASE
WHEN ID = #NewId
THEN #OldId
ELSE #NewId
END
WHERE ID IN (#NewId, #OldId)
Here is a full example
DECLARE #Table TABLE(
ID INT,
Name VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'A'
INSERT INTO #Table SELECT 2,'B'
DECLARE #NewName VARCHAR(20),
#OldName VARCHAR(20)
SELECT #NewName = 'A',
#OldName = 'B'
DECLARE #NewId INT,
#OldId INT
SELECT #NewId = ID FROM #Table WHERE [Name] = #NewName
SELECT #OldId = ID FROM #Table WHERE [Name] = #OldName
SELECT *
FROM #Table
UPDATE #Table
SET ID = CASE
WHEN ID = #NewId
THEN #OldId
ELSE #NewId
END
WHERE ID IN (#NewId, #OldId)
SELECT *
FROM #Table
This script works if the ID is not a primary Key
CREATE PROCEDURE dbo.procName
#OldName NVARCHAR(128),
#NewName NVARCHAR(128)
As
DECLARE #NewId INT,
#OldId INT
SELECT #NewId = ID FROM Table1 WHERE [Name] = #NewName
SELECT #OldId = ID FROM Table1 WHERE [Name] = #OldName
UPDATE Table1
SET ID = CASE
WHEN ID = #NewId
THEN #OldId
ELSE #NewId
END
WHERE ID IN (#NewId, #OldId)
SELECT *
FROM Table1
go
Your current code fails because:
You Look for #NewId0, and set it to #Number (which is 0)
You then look for #OldId0, and set it to #NewId1
You then look for #NewId0 again... but two lines back, you set it to 0, so it's not in the table any more
I like #astander's solution (upvoted), saved me writing it out myself.
BUT... your comment, "...ID is a Primary Key", raises all kinds of red flags. You really, really don't want to change primary key values [insert long discussion from past classes about primary keys and relational integrity here]. Figure out why you think you need to do it, and then figure out another way to implement that business requirement, such as:
Don't change the IDs, change everything else (name, description, cost, whatever)
Create completely new entries and drop (or mark as completed, discareded, or junk) the old ones
Implement some clever logic based on the underlying business requirements.
under stand the concerns with changing PKs but it has to be done as it would take too long to change all the other stuff. That said I have come up with an answer. This is only the first part of a long script so again its not perfect:
CREATE PROCEDURE dbo.ID #OldName NVARCHAR(128),
#NewName NVARCHAR(128)
AS
DECLARE #NewId INT,
#OldId INT
CREATE TABLE TmpTable (ID INT,Name NVARCHAR(128))
INSERT INTO TmpTable (Name,ID)
VALUES (#NewName,(SELECT ID FROM Table1 WHERE [Name] = #NewName));
INSERT INTO TmpTable (Name,ID)
VALUES(#OldName,(SELECT ID FROM Table1 WHERE [Name] = #OldName))
UPDATE Table1 SET ID = 11 WHERE [NAME] = #NewName
UPDATE Table1 SET ID = 10 WHERE [NAME] = #OldName
UPDATE Table1 SET ID = (SELECT ID FROM TmpTable where Name = #NewName)WHERE [Name] = #OldName
UPDATE Table1 SET ID = (SELECT ID FROM TmpTable where Name = #OldName) WHERE [Name] = #NewName
DROP TABLE TmpTable
go
"11" and "10" were selected as they are not in the table my next mission will be to query table1 and for a random number that dosent exist then use that number to temprary repplace the ID before updating the new ones.
Thanks