Throwing conversion error while pass the value directly - sql
This code throws an error when pass the value directly, but it doesn't show any error if pass the value by using parameter.
--It throws an Error
DECLARE #sql NVARCHAR(4000)
DECLARE #ID INT=1234
SET #sql = N'select
[count]
FROM dbo.Table_1 AS t
JOIN dbo.table_2 AS t2 ON t.store_number = t2.store_number
AND t2.[year] = 17
AND t2.week_of_year = 6
AND t2.day_of_week = 2
WHERE t.RC_ID = #ID'
EXEC sp_executesql #sql
-- It throws an error
select
[count]
FROM dbo.Table_1 AS t
JOIN dbo.table_2 AS t2 ON t.store_number = t2.store_number
AND t2.[year] = 17
AND t2.week_of_year = 6
AND t2.day_of_week = 2
WHERE t.ID = 1234
-- IT WORKS
DECLARE #sql
DECLARE #ID INT
SET #ID = 1234
select
[count]
FROM dbo.Table_1 AS t
JOIN dbo.table_2 AS t2 ON t.store_number = t2.store_number
AND t2.[year] = 17
AND t2.week_of_year = 6
AND t2.day_of_week = 2
WHERE t.ID = #ID
The Error is :
Msg 245, Level 16, State 1, Line 1 Conversion failed when converting
the varchar value 'TEST' to data type int.
But there is No data like 'Test' in the table.
One of your values that you are comparing as integers contains a bad value:
select t2.*
from table_2 t2
where try_convert(int, year) is null or try_convert(int, week_of_year) is null or
try_convert(int, day_of_week) or try_convert(int, id) is null;
Whether the error occurs depends on the execution plan.
from what i see you are trying to use a parameter(#id) into the sp_executeSQL without never passing it. A quick fix would be to do something like that
DECLARE #sql NVARCHAR(4000)
DECLARE #ID INT = 10
SET #sql = N'select
[count]
FROM dbo.Table_1 AS t
JOIN dbo.table_2 AS t2 ON t.store_number = t2.store_number
AND t2.[year] = 17
AND t2.week_of_year = 6
AND t2.day_of_week = 2
WHERE t.RC_ID = ' + cast(#ID as nvarchar(20))
EXEC sp_executesql #sql
Hope this helps
One of your table columns that you are filtering is not a numeric data type. When you do
WHERE VarcharColumn = 1
The SQL Server engine will always try to convert the most complex type to the simplest one, in this case "1" is a integer and VarcharColumn is VARCHAR, so the engine will try to convert all the values stored in VarcharColumn to integer before filtering by value 1. Since at least one value stored there is not an integer ("TEST") then the conversion fails and that message pops up.
You have 2 solutions:
Validate and fix all your values in those columns so they are actually numbers and alter the data type to the corresponding one.
Compare against the same type. WHERE Column = '1'
Of course always try to keep your data types in check.
Also in your dynamicSQL query, the declaration of the #ID must be inside your script (it's also missing an initial value).
DECLARE #sql NVARCHAR(4000)
SET #sql = N'
DECLARE #ID INT = 1
select
[count]
FROM dbo.Table_1 AS t
JOIN dbo.table_2 AS t2 ON t.store_number = t2.store_number
AND t2.[year] = 17
AND t2.week_of_year = 6
AND t2.day_of_week = 2
WHERE t.RC_ID = #ID'
EXEC sp_executesql #sql
The reason for the error poping up 'sometimes' is because the different forms of your statement are making the execution plan do things in different order. If it tries to convert the varchar value to int first, it will fail. If it tries to convert the int value to varchar (for example) then it won't fail.
To find the problem, try this:
SELECT
*
FROM
dbo.Table_1 AS T
WHERE
CONVERT(VARCHAR(200), T.store_number) = 'Test' OR
CONVERT(VARCHAR(200), T.ID) = 'Test'
SELECT
*
FROM
dbo.table_2 AS T
WHERE
CONVERT(VARCHAR(200), T.store_number) = 'Test' OR
CONVERT(VARCHAR(200), T.[year]) = 'Test' OR
CONVERT(VARCHAR(200), T.week_of_year) = 'Test' OR
CONVERT(VARCHAR(200), T.day_of_week) = 'Test'
Related
SET more than 1 row output into 1 variable
I am wanting to be able to save more than just 1 output from a SELECT query in a single variable. Currently I am gathering my needed data like so: DECLARE #something1 VARCHAR(MAX) DECLARE #something2 VARCHAR(MAX) DECLARE #something3 VARCHAR(MAX) SET #something1 = ( SELECT Custom AS 'XXL Format' FROM tblData WHERE ID = 1); SET #something2 = ( SELECT Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format' FROM tblData WHERE ID = 1) SET #something3 = ( SELECT tbl1.paper, tbl2.type FROM tblData AS tbl1 JOIN tblData2 tbl2 ON tbl1.ID = tbl2.ID WHERE ID = 1); I have the following demo that shows what I am wanting to do DECLARE #tester VARCHAR(MAX) SET #tester = ( SELECT tbl1.Custom AS 'XXL Format', tbl1.Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format' tbl1.paper, tbl2.type FROM tblData AS tbl1 JOIN tblData2 tbl2 ON tbl1.ID = tbl2.ID WHERE ID = 1); I get the error of: Only one expression can be specified in the select list when the subquery is not introduced with EXISTS Both demos can be found here I have tried to set the variable to "table" and store the data like that but that also does not seem to work correctly [I'm sure I am doing something wrong - that may be the answer to this question I'm asking] How can I just use 1 variable for all that the above query outputs?
Your error is that the subquery returned more than one value. You can use top if you don't care which value gets assigned: SET #tester = (SELECT TOP (1) description FROM ForgeRock);
You have to return only one value you can try top or limit like SET #tester = (SELECT TOP 1 description FROM ForgeRock); or SET #tester = (SELECT description FROM ForgeRock LIMIT 1);
So I guess I was correct with the set the variable to a temp "table". I finally just now got it to work for my needs! DECLARE #tmpTbl table (_xml, _parsedXML, _paper, _type) INSERT INTO #tmpTbl SELECT tbl1.Custom AS 'XML Format', tbl1.Custom.value('(/Individual/text())[1]', 'varchar(MAX)') AS 'Non XML Format', tbl1.paper, tbl2.type FROM tblData AS tbl1 JOIN tblData2 AS tbl2 ON tbl1.ID = tbl2.ID WHERE ID = 1; DECLARE #something1 VARCHAR(MAX) = (SELECT _xml FROM #tmpTbl); DECLARE #something2 VARCHAR(MAX) = (SELECT _parsedXML FROM #tmpTbl); DECLARE #something3 VARCHAR(MAX) = (SELECT _paper FROM #tmpTbl); DECLARE #something4 VARCHAR(MAX) = (SELECT _type FROM #tmpTbl); DELETE FROM #tmpTbl --Not really needed but nice to be offical :) This above stores the values into one place. Although its not inside 1 variable I guess having to create a temp table isn't all that bad for the database/performance...
MSSQL says I am trying to convert a varchar to a string when I'm not
So I have this fairly long procedure at Work that I just made. What it does it not that important, but the end result is what matters. I need to count some different types of descriptions in a table and that Works fine. I then need to take the two things that I Count and put them in a string that I return to my software. However, every time I run this procedure it gives me this: Msg 245, Level 16, State 1, Procedure WorkDays, Line 43 Conversion failed when converting the varchar value 'FlightDeck:161,CabinCrew:189' to data type int. I just can't figure out why it keeps telling me this when I am not trying to convert a varchar to an int but rather ints to a single varchar. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[WorkDays] #requestedDate nchar(10) AS SET ANSI_WARNINGS OFF DECLARE #date as nchar(10) = '' DECLARE #returnVal as varchar(30) = '' DECLARE #flightDeck as int = 0 DECLARE #cabinCrew as int = 0 BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; SET #date = #requestedDate SELECT #flightDeck = SUM(CASE WHEN dbo.Crew_Category.Description LIKE 'Flight Deck' THEN 1 END), #cabinCrew = SUM(CASE WHEN dbo.Crew_Category.Description LIKE 'Cabin Crew' THEN 1 END) FROM dbo.CrewMember INNER JOIN dbo.Crew_Category ON dbo.CrewMember.CrewCategorySeqNo = dbo.Crew_Category.CrewCategorySeqno WHERE (dbo.Crew_Category.Description = N'Flight Deck' OR dbo.Crew_Category.Description = N'Cabin Crew') AND (dbo.CrewMember.EmploymentEndDate > #date) AND dbo.CrewMember.CrewSeqno NOT IN ( SELECT CrewMember_1.CrewSeqno FROM dbo.CrewMember AS CrewMember_1 INNER JOIN dbo.CrewReqAsg ON CrewMember_1.CrewSeqno = dbo.CrewReqAsg.crewSeqno INNER JOIN dbo.activity ON dbo.CrewReqAsg.act_seqno = dbo.activity.act_seqno INNER JOIN dbo.ActivityType ON dbo.activity.actType_seqno = dbo.ActivityType.actType_seqno INNER JOIN dbo.ActivityCategory ON dbo.ActivityType.ActCat_seqno = dbo.ActivityCategory.actCat_seqno INNER JOIN dbo.Crew_Category AS Crew_Category_1 ON CrewMember_1.CrewCategorySeqNo = Crew_Category_1.CrewCategorySeqno WHERE ( dbo.ActivityCategory.Category = N'Ferie' OR dbo.ActivityCategory.Category = N'Fridage' OR dbo.ActivityCategory.Category = N'Sygdom') AND (Crew_Category_1.Description = N'Flight Deck' OR Crew_Category_1.Description = N'Cabin Crew') AND (LEFT(dbo.activity.Start,10) LIKE #date)); SET #returnVal = 'FlightDeck:'+CAST(#flightDeck AS varchar); SET #returnVal += ',CabinCrew:'+CAST(#cabinCrew AS varchar); END RETURN #returnVal It's been a while since I've had to do this so perhaps I just forgot something fundamental. Please help me figure out why this happens? :)
Yes, you forgot something fundamental. To return data to the caller, use SELECT, not RETURN. You need SELECT #returnVal
Modifying XML Column with Select Query
I have a SQL Server table with a XML column which got information in. I want to select whole ID's from this table and modify my another xml column. My query is; declare #name nvarchar(max); set #name = 'mark'; update table1 set table1.Information1.modify('insert <s n="' + cast((select cast(table2.Information2 as varchar(100)) from table2 where table2.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1) as varchar(400)) + '"/> into (/r)[1]') where table1.Name = #name; I'm getting Msg 8172, Level 16, State 1, Line 5 The argument 1 of the XML data type method "modify" must be a string literal. Any help would be nice.
Are you sure you want to put the whole xml into attribute of Information1, like this: declare #name nvarchar(max), #data xml select #name = 'mark' select cast(Information2 as varchar(100)) as n from table2 as t where t.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1 for xml raw('s') update table1 set Information1.modify('insert sql:variable("#data") into (/r)[1]') sql fiddle demo
Much as you are doing with the filtering, you need to use sql:variable. You can't build up a string inside a .modify function. declare #newData xml select #newData = '<s n="' + cast(table2.Information2 as varchar(100)) + '"/>' from table2 where table2.Information2.exist('/r/s[#n=sql:variable("#name")]') = 1 update table1 set Information1.modify('insert sql:variable("#newData") into (/r)[1]')
SQL WHERE ... IN clause with possibly null parameter
I am having some problems with my WHERE clause (using SQL 2008) . I have to create a stored procedure that returns a list of results based on 7 parameters, some of which may be null. The ones which are problematic are #elements, #categories and #edu_id. They can be a list of ids, or they can be null. You can see in my where clause that my particular code works if the parameters are not null. I'm not sure how to code the sql if they are null. The fields are INT in the database. I hope my question is clear enough. Here is my query below. BEGIN DECLARE #elements nvarchar(30) DECLARE #jobtype_id INT DECLARE #edu_id nvarchar(30) DECLARE #categories nvarchar(30) DECLARE #full_part bit DECLARE #in_demand bit DECLARE #lang char(2) SET #jobtype_id = null SET #lang = 'en' SET #full_part = null -- full = 1, part = 0 SET #elements = '1,2,3' SET #categories = '1,2,3' SET #edu_id = '3,4,5' select jobs.name_en, parttime.fulltime_only, jc.cat_id category, je.element_id elem, jt.name_en jobtype, jobs.edu_id minEdu, education.name_en edu from jobs left join job_categories jc on (jobs.job_id = jc.job_id) left join job_elements je on (jobs.job_id = je.job_id) left join job_type jt on (jobs.jobtype_id = jt.jobtype_id) left join education on (jobs.edu_id = education.edu_id) left join (select job_id, case when (jobs.parttime_en IS NULL OR jobs.parttime_en = '') then 1 else 0 end fulltime_only from jobs) as parttime on jobs.job_id = parttime.job_id where [disabled] = 0 and jobs.jobtype_id = isnull(#jobtype_id,jobs.jobtype_id) and fulltime_only = isnull(#full_part,fulltime_only) -- each of the following clauses should be validated to see if the parameter is null -- if it is, the clause should not be used, or the SELECT * FROM ListToInt... should be replaced by -- the field evaluated: ie if #elements is null, je.element_id in (je.element_id) and je.element_id IN (SELECT * FROM ListToInt(#elements,',')) and jc.cat_id IN (SELECT * FROM ListToInt(#categories,',')) and education.edu_id IN (SELECT * FROM ListToInt(#edu_id,',')) order by case when #lang='fr' then jobs.name_fr else jobs.name_en end; END
Something like and (#elements IS NULL OR je.element_id IN (SELECT * FROM ListToInt(#elements,','))) and (#categories IS NULL OR jc.cat_id IN (SELECT * FROM ListToInt(#categories,','))) .... should do the trick
je.element_id IN (SELECT * FROM ListToInt(#elements,',')) OR #elements IS NULL that way for each one
Have you tried explicitly comparing to NULL? and (#elements is null or je.element_id IN (SELECT * FROM ListToInt(#elements,',')) And so on.
Convert Comma Delimited String to bigint in SQL Server
I have a varchar string of delimited numbers separated by commas that I want to use in my SQL script but I need to compare with a bigint field in the database. Need to know to convert it: DECLARE #RegionID varchar(200) = null SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' SELECT a.ClassAdID, -- 1 a.AdURL, -- 2 a.AdTitle, -- 3 a.ClassAdCatID, -- 4 b.ClassAdCat, -- 5 a.Img1, -- 6 a.AdText, -- 7 a.MemberID, -- 9 a.Viewed, -- 10 c.Domain, -- 11 a.CreateDate -- 12 FROM ClassAd a INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID INNER JOIN Region c ON c.RegionID = a.RegionID AND a.PostType = 'CPN' AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0 AND a.RegionID IN (#RegionID) AND Viewable = 'Y' This fails with the following error: Error converting data type varchar to bigint. RegionID In the database is a bigint field.. need to convert the varchar to bigint.. any ideas..? Many thanks in advance, neojakey
create this function: CREATE function [dbo].[f_split] ( #param nvarchar(max), #delimiter char(1) ) returns #t table (val nvarchar(max), seq int) as begin set #param += #delimiter ;with a as ( select cast(1 as bigint) f, charindex(#delimiter, #param) t, 1 seq union all select t + 1, charindex(#delimiter, #param, t + 1), seq + 1 from a where charindex(#delimiter, #param, t + 1) > 0 ) insert #t select substring(#param, f, t - f), seq from a option (maxrecursion 0) return end change this part: AND a.RegionID IN (select val from dbo.f_split(#regionID, ',')) Change this for better overall performance: AND DATEDIFF(d, 0, GETDATE()) <= ExpirationDate
Your query does not know that those are separate values, you can use dynamic sql for this: DECLARE #RegionID varchar(200) = null SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' declare #sql nvarchar(Max) set #sql = 'SELECT a.ClassAdID, -- 1 a.AdURL, -- 2 a.AdTitle, -- 3 a.ClassAdCatID, -- 4 b.ClassAdCat, -- 5 a.Img1, -- 6 a.AdText, -- 7 a.MemberID, -- 9 a.Viewed, -- 10 c.Domain, -- 11 a.CreateDate -- 12 FROM ClassAd a INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID INNER JOIN Region c ON c.RegionID = a.RegionID AND a.PostType = ''CPN'' AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0 AND a.RegionID IN ('+#RegionID+') AND Viewable = ''Y''' exec sp_executesql #sql
I use this apporach sometimes and find it very good. It transfors your comma-separated string into an AUX table (called #ARRAY) and then query the main table based on the AUX table: declare #RegionID varchar(50) SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' declare #S varchar(20) if LEN(#RegionID) > 0 SET #RegionID = #RegionID + ',' CREATE TABLE #ARRAY(region_ID VARCHAR(20)) WHILE LEN(#RegionID) > 0 BEGIN SELECT #S = LTRIM(SUBSTRING(#RegionID, 1, CHARINDEX(',', #RegionID) - 1)) INSERT INTO #ARRAY (region_ID) VALUES (#S) SELECT #RegionID = SUBSTRING(#RegionID, CHARINDEX(',', #RegionID) + 1, LEN(#RegionID)) END select * from your_table where regionID IN (select region_ID from #ARRAY) It avoids you from ahving to concatenate the query string and then use EXEC to execute it, which I dont think it is a very good approach. if you need to run the code twice you will need to drop the temp table
I think the answer should be kept simple. Try using CHARINDEX like this: DECLARE #RegionID VARCHAR(200) = NULL SET #RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' SELECT 1 WHERE Charindex('834', #RegionID) > 0 SELECT 1 WHERE Charindex('999', #RegionID) > 0 When CHARINDEX finds the value in the large string variable, it will return it's position, otherwise it return 0. Use this as a search tool.
The easiest way to change this query is to replace the IN function with a string function. Here is what I consider the safest approach using LIKE (which is portable among databases): AND ','+#RegionID+',' like '%,'+cast(a.RegionID as varchar(255))+',%' Or CHARINDEX: AND charindex(','+cast(a.RegionID as varchar(255))+',', ','+#RegionID+',') > 0 However, if you are explicitly putting the list in your code, why not use a temporary table? declare #RegionIds table (RegionId int); insert into #RegionIds select 853 union all select 834 union all . . . select 303 Then you can use the table in the IN clause: AND a.RegionId in (select RegionId from #RegionIds) or in a JOIN clause.
I like Diego's answer some, but I think my modification is a little better because you are declaring a table variable and not creating an actual table. I know the "in" statement can be a little slow, so I did an inner join since I needed some info from the Company table anyway. declare #companyIdList varchar(1000) set #companyIdList = '1,2,3' if LEN(#companyIdList) > 0 SET #companyIdList = #companyIdList + ',' declare #CompanyIds TABLE (CompanyId bigint) declare #S varchar(20) WHILE LEN(#companyIdList) > 0 BEGIN SELECT #S = LTRIM(SUBSTRING(#companyIdList, 1, CHARINDEX(',', #companyIdList) - 1)) INSERT INTO #CompanyIds (CompanyId) VALUES (#S) SELECT #companyIdList = SUBSTRING(#companyIdList, CHARINDEX(',', #companyIdList) + 1, LEN(#companyIdList)) END select d.Id, d.Name, c.Id, c.Name from [Division] d inner join [Company] c on d.CompanyId = c.Id inner join #CompanyIds cids on c.Id = cids.CompanyId