Argument type varchar invalid - sql

I have SQL code that I am running and am getting an error when I pass in certain information.
select * from OBX.BTOCUST
--where [CUSTID] like 'sci'
--order by BRANDING desc
where BRANDING not like '0x4767374ADABABBAB9B96865669F9D9DE4E3E3838182ACABAB9E9D9DE3E3E3848182231F20000000FFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021F90401000026002C000000000D023C000006FF409370482C1A8FC8A472C96C3A9FD0A8744AAD5AAFD8AC76CBED7ABFE0B0784C2E9BCFE8B47ACD6EBBDFF0B87C4EAFDBEFF8BC7ECFEFFBFF8081828384858687884A0D03238D8E8F9091928E1520178998999A9B9C61148F1403A2A3A4A5A68CA1A49F941A9DAEAFB0B19A0C8C8D031925B9BABBBCBDB9231BBD17138F0CB2C7C8C9CA710C8D1505BED1D225CD1DD21AAB13CBDBDCDDDE57C4230CD3BC171916161ABD1613E40CE1DFF1F2F3F18D13E3E4BF8FE8C41B161C8D2EE42BF18982317A08132AD4147060090C8E0658CB550092C38A231A2CDCC8B1239F108D1C426C84A1D7C8900E378CA0E0B1A5CB976C2A8C2839F051B40EAB1CEA83C9B3A7CFFF2D204708CC77C166340FC07496687444410005044C18C882202A9600010008D17A27C0D49F607F3698E910A92369D59432024184C001AB041670B5F28044042B0B489018428084803912B826207120AC619E1039A434EA6B98D212163212A94BC4C0DC2A042024C0AC570291057FE590982B40C1E1D32D19411B98E19187C7D32A6A1C2280F083219B8538BD6D820080DF261064FDCDF5B76500B98560B52A4438F32100F44230325D7780E4267E47BD9E1D000103DC8960259200387821049C561592E0008907067C0367FF60BD89F200A6064080BA7F32D50E7500092EB0F922DB647A91C01F797209C05F667A99A0575D119AA0800006E4151A01A54170FF406E0840A0C0874540306112092C306268128E2601612D3E901709D5C58580020E14A797027A6DE600027915D6A25E0140B89709260610819000B827416D47FA27E52B003A140981BC4C32823407F23523090E9826D501A60DA6557424BCB8978942F66642007E09915776605A4842543012E1805E975546A6092F5AD5D99E85E9B50001115438A78424B6E8C09E0920E0806F15B6A8E391242CD09B82424089E67353868A4995034536A02F66356201395D1281807B9D59FA1B8C685E566175708656A183B2562A44827D0E5161749AB61800117C6E4AC2541526F86B94161E60008F51264BE75E2F1E6B426DA6D576ACB5A2868B08A9039DE40896BA68C0FF18979219E156827D9180D5BCD716C127A2CAC5D9A2BDF2D2FB995E0B1A316CB3A3215BB0A5FB0EF9AC1119566A2D9ADBCADBA9C4DE222CEEC585905BEE95BC9C54413EAD6E8B5DA26806BC95AFC1193A44AE0B1BFC15C37A3980C4C0325BFC2C577A318B29C195D108F1CD27AF2971C4FC550C2EC648FFA1713EEF70ACCB2A23BC960BBABB842C008BD915E6DEA44278F6335F4EAEACAFB578DA859E116A5E96C06D7BEA4623D0C2161C6FCB31B73CF1ACD51E0C310243E73595D107272D381F4B0F148E96E71600113EBD58ED80009BBD4A5B82DA52889D54770D9128D77CEB45A2017B122666110F380900021124A724010EB47962DC0200505BB123C697FF267ABECE48AD5C48D669028542EC09009C51B16EF6EB83278F47E14C1F7E6E073249C2EE6CCAF9F6A4042F9B108100D581E72F1197CDBBA0015733C72186491080C0D559952880572B63F5329FEB3FC01CF9B10F215CFB42907FDB855CE19067BCA72D023C807B0BDA5F56E6953DE539300ECC2347AA1EA198622C0525066AD7318EF6C00E2A248225D8C0C77821204904C328C4186106A9270B0E7AF085F20061D4CA01354850E08228890C4D56980CE4C1F087DF90E144A6060A8C48628491615CE33408C4263A510C32DCC505A046810B18311234F1C00062C3C4277AF18B58882052B6A80F5BE4425D93D049C8C0C8C6363E2182E138E3238672920906FFE3224C24CE6F2E0707F56DE1387C74A320953682D5F402205ACA45334882C8460C11645DFCDA12B425866269EF3D5B60D920370908E6A9441D68DC870756010DE729658D924C1F25C310A50440005456D0242767B907E68DA01DB9A8E12330B01A8BA83192283B425C56F905BE854196B44CA61D4048114890314B8EB8E12F59582F2138094A034C509C52149D0799285366A350E8C4149711DDE9597C6AD2D00EA0A20384E69BAFCA5366DA79A87C614D99F8846021F3D1C846480D9A24392530A3E42967454C5B06F8D3C0C099B99CD5A55810B80B9C3C53CD834A8504A609D4B52230B7DE49F4766FD2573E47FA066696A09F235047C72C38CD227C0D70FF47AA58AF8E94CA08FD2C009A7A51685E2AAF8E12AB9A1582534EF5854C921A350D26BDE23E7911BDA408949A3CFDD6AE8646247FD5742F920480868236B9AC2C14A8D0DAD656437ACFA39A950C2625C82354AA0B5339F231A8AC144C27A62D80B9146536AD108F84A3AFA81A806660D58D7BC86ACFB31AB60C6955892356B58BA66E09AE03EDAAC22C6A82AD3DE7AAF57A17612B5AB1B6D9693A3FAB10AC365BD4C39A960B696D8D237658C64628913591A5EB646B2301DFC0295317E2AAC1EA8526058CF553B2E59156E03495D0EEEC4E632DED69977B85B1B0761AAAC5E02944A19611B0257EE27B13568627BFE6684673F993CAF7B4BB407A012002FC09FD0004BEE2BFE0581502EFFBCABCCACB9FF3668E7BD9192F73F75B0575A9301FEBBA86950AC9DF021F4626CF95C614CF350D0A28A6262330B084C13216690EA4288B8DC63F02C494097B98270DD1497457C2810258600314C0C06BAFD188063000040DF8C08767CC1167AC18BA8A7D4405FE3990823020C51FA88036684C647A8CE5960542073A86A293458280011F10C5073650E42ACB63911430648174820D7B984023231800950B60E53277E370CFDC3224ED610C306B200426B88499E7BC0C5D4EF7CE781605242AD08A215440232AA1B3A0930165E721EED087967111821C66390FFAD1908EB4A4274DE94A5BFAD298CEB4A637CDE94E7B5A994100003B'
When I uncomment the --where [CUSTID] like 'sci' and comment out branding the query runs and am able to see results. But when I run where branding I get an error:
Msg 8116, Level 16, State 1, Line 1
Argument data type varchar is invalid for argument 2 of like function.
also another thing is when i uncomment the order by BRANDING desc it gives me another error.
that error is
Msg 306, Level 16, State 2, Line 3 The text, ntext, and image data
types cannot be compared or sorted, except when using IS NULL or LIKE
operator.
What do I need to do to get the command to actually work?

This error message is what you get if BRANDING is of type IMAGE, which is incomparable (as in, literally, it cannot be compared in any way, not even to another IMAGE). To overcome the limitations of this type, SQL Server 2005 introduced the VARBINARY(MAX) type, which has the same purpose but isn't burdened with the special case handling that IMAGE requires (likewise, (N)VARCHAR(MAX) was introduced to replace (N)TEXT). IMAGE should not be used for new work; VARBINARY(MAX) is superior in all respects. If existing IMAGE columns can be changed to VARBINARY(MAX), do so.
If that isn't possible, the IMAGE can still be converted on the fly. In the query above:
select * from OBX.BTOCUST
where CONVERT(VARBINARY(MAX), BRANDING) <> 0x476737.....00003B
Here the 0x476737.... is a BINARY literal. To convert a hexstring to a binary, use CONVERT(VARBINARY(MAX), #string, 1) (with leading "0x") or CONVERT(VARBINARY(MAX), #string, 2) (without leading "0x").

Convert your image or text or ntext column data type to varbinary(max), varchar(max) or nvarchar(max).
The image, text, and ntext data types are deprecated and will be removed in a future version of SQL Server. They are very difficult and awkward to work with. The varchar(max) and nvarchar(max) have all the benefits of nearly unlimited string size, and none of the drawbacks of text or ntext. They also work with all the normal string functions you'd expect.

This is a quick and dirty way of doing it that I just put together, but keep in mind what you are asking of your server in the absence of fulltext. It ignores the data type mismatches as low level errors in your message output. You can check the message output for a rudimentary sort of progress on it as it is running.
Declare #SearchString nvarchar(50) = 'SEARCH STRING HERE'
Declare #TableList Table (TableName nvarchar(128))
Declare #Table nvarchar(128)
Declare #ColumnList Table (ColumnName nvarchar(128))
Declare #Column nvarchar(128)
Declare #Results Table (TableName nvarchar(128), ColumnName nvarchar(128), String nvarchar(max))
Declare #cmd nvarchar(max)
Insert Into #TableList
Select TABLE_NAME From INFORMATION_SCHEMA.Tables Where Table_Type = 'BASE TABLE'
While Exists (Select 1 From #TableList)
Begin
Set #Table = (Select Top 1 TableName From #TableList)
Print 'Searching '+#Table+'...'
Insert Into #ColumnList
Select Column_Name From INFORMATION_SCHEMA.Columns Where Table_Name = #Table
While Exists (Select 1 From #ColumnList)
Begin
Set #Column = (Select Top 1 ColumnName From #ColumnList)
Print 'Searching ' +#Table + '.' + #Column+'...'
Set #cmd = 'Select '''+#Table+''', '''+#Column+''', '+#Column+' From '+#Table+' Where '+#Column+' Like ''%'+#SearchString+'%'''
--Select #cmd
Insert Into #Results
Exec (#cmd)
Delete From #ColumnList Where ColumnName = #Column
End
Delete From #TableList Where TableName = #Table
End
Select * From #Results

Related

Generating filed name with concat

My table has column names m1,m2,m3...,m12.
I'm using iterator to select them and insert them one by one in another table.
In this iterator I'm trying to generate filed names with:
'['+concat('m',cast(#P_MONTH as nvarchar))+']'
where #P_MONTH is incrementing in each loop.
so for #P_MONTH = 1 this suppose to give [m1] which works fine.
But when I run query I get:
Conversion failed when converting the nvarchar value '[m1]' to data
type int.
And if I put simply [m1] in that select it works ok.
How to concat filed name so it can be actually interpreted as filed name from certain table?
EDIT
Here is full query:
DECLARE #SQLString nvarchar(500),
#P_YEAR int,
#P_MONTH int = 1
set #P_YEAR = 2018
WHILE #P_MONTH < 13
BEGIN
SET #SQLString =
'INSERT INTO [dbo].[MASTER_TABLE]
(sector,serial,
date, number, source)'+
'SELECT ' + '[SECTOR],[DEPARTMENT]' +
QUOTENAME(cast(CONVERT(datetime,CONVERT(VARCHAR(4),#P_YEAR)+RIGHT('0'+CONVERT(VARCHAR(2),#P_MONTH),2)+'01',5) as nvarchar))+
QUOTENAME ('M',cast(#P_MONTH as nvarchar)) +
'EMPLOYED' +
'FROM [dbo].[STATS]'+
'where YEAR= #P_YEAR'
EXECUTE sp_executesql #SQLString
SET #P_MONTH = #P_MONTH + 1
END
It's still not working. It executes successfully but it does nothing.
Good day,
Let's create a simple table for the sake of the explanation
DROP TABLE IF EXISTS T
GO
CREATE TABLE T(a1 INT)
GO
INSERT T(a1) VALUES (1),(2)
GO
SELECT a1 FROM T
GO
When we are using a query like bellow, the server parse the text as a value and not as a column name
DECLARE #String NVARCHAR(10)
SELECT #String = '1'
--
SELECT '['+concat('a',cast(#String as nvarchar))+']'
FROM T
GO
This mean that the result will be 2 rows with no name for the column and the value will be "[a1]"
Moreover, the above query uses the brackets as part of the string.
One simple solution is to use the function QUOTENAME in order to add brackets around a name.
Another issue in this approach is the optional risk of SQL Injection. QUOTENAME might not be perfect solution but can help in this as well.
If we need to use entities name dynamically like in this case the column name then for most cases using dynamic query is the best solution. This mean to use the Stored Procedure sp_executesql as bellow
DECLARE #String INT
SELECT #String = 1
DECLARE #SQLString nvarchar(500);
SET #SQLString =
'SELECT ' + QUOTENAME(concat('a',cast(#String as nvarchar))) + ' FROM T'
EXECUTE sp_executesql #SQLString
GO

SQL Server passing identifiers to stored procedures/dynamic SQL

Background:
SQL Server Management Studio allows to define own query shortcuts (Tools > Options > Environment > Keyboard > Query Shortcuts):
Image from: http://social.technet.microsoft.com/wiki/contents/articles/3178.how-to-create-query-shortcuts-in-sql-server-management-studio.aspx
my_schema.my_table
-- highlight it
-- press CTRL + 3 and you will get the number of rows in table
It works ok, but it concatenates query in basic form (as far as I know only at the end). Query:
SELECT COUNT(*) FROM my_schema.my_table;
Attempt #1
Now I want to write something more specific, for example pass/concatenate table name to following query (this is just example):
SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(...)
So when I write in query shortcuts:
SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID('
I have to use:
my_schema.my_table')
-- highlight it
-- press CTRL + 3
The additional ') is very ugly and inconvenient.
Attempt #2:
The second trial is to use Dynamic-SQL:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,
Executing:
my_table
-- highligt it
-- and run
LiveDemo
Works also when table name is quoted [my_table]. As long as object is in dbo(default) schema.
The problem is that when table has schema it won't work:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,
Executing:
my_schema.my_table
[my_schema].[my_table]
LiveDemo2
Incorrect syntax near '.'.
Of course I could write:
EXEC dbo.sp_executesql
N'SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(#obj_name)'
,N'#obj_name SYSNAME'
,'
and call it as:
[my_schema].[my_table]'
But additional ' is also ugly and inconvenient.
Questions:
Is it possible to pass value, to query shortcuts window, in the middle (positional or even more than one value)?
Is it possible to pass do stored_procedure/dynamic-sql qualified identifier without wraping it with ', "?
Remarks:
I do not search for plugins to SSMS
I do not want to wrap object_name as "my_schema.my_table"
I know there is sp_helptext (this is just example, I search for method)
First question is tool specific (I am aware of it), but second is about SQL Server.
EDIT:
To clarify passing identifier to SP without ' or ":
CREATE TABLE dbo.my_table(col INT);
GO
CREATE PROCEDURE dbo.my_proc
#a SYSNAME
AS
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#a)
GO
EXEC dbo.my_proc
#a = my_table;
EXEC dbo.my_proc
#a = dbo.my_table;
-- Incorrect syntax near '.'.
LiveDemo3
1. Is it possible to pass value, to query shortcuts window, in the middle?
To my knowledge, there is no workaround to achieve this.
1-b. Is it possible to pass more than one value?
It can be done for string values using a separator character and then splitting the value on the other side. Sadly, there isn't many special character to fulfill this job because they pretty much all raise a syntax error. However '#' could be a wise choice because it's already a special character for SQL for temp table going in tempDB. Just check if you don't already have identifier that are using it because it's permitted by SQL (tough, it's forbidden as first char).
Here is an example of this :
Create a stored procedure to receive the arguments into one single string and split the string to have each arguments.
CREATE PROCEDURE sp_PassingMultipleStringValues
#Param1 NVARCHAR(MAX)
AS
--Here I'm using a XML split, but feel free to use any string split function you already have.
DECLARE #xml AS XML,
#separator AS VARCHAR(1)
SELECT #separator ='#',
#xml = CAST('<X>'+ (REPLACE(#Param1,#separator ,'</X><X>') +'</X>') AS XML)
SELECT N.value('.', 'VARCHAR(200)') AS value
FROM #xml.nodes('X') as T(N)
--Do whatever is needed with them
Then configure your shortcut as seem on this image. (Note the space at the end)
Result :
2. Is it possible to pass to a stored_procedure/dynamic-sql qualified identifier without wraping it with ', "?
Do you have multiple schema with the same identifier?
Because if not, what about retrieve it on the other side using sys.schemas instead of passing it?
Instead of having an inconvenient character to type at the end, you would have fewer things to type.
With the retrieved schema, you can then do dynamic SQL for whatever is needed with it.
SELECT #Param1 = REPLACE(REPLACE(#Param1, '[', ''), ']', '')
SELECT TOP 1 #Param1 = [Schema].name + '.' + #Param1
FROM sys.objects AS obj
JOIN sys.schemas AS [Schema] ON obj.schema_id = [Schema].schema_id
WHERE obj.name = #Param1
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#Param1)
DECLARE #Query NVARCHAR(MAX) = 'SELECT TOP 1 * FROM ' + #Param1
EXEC sp_sqlexec #Query
If you do want to handle two different schema with the same identifier then it's still feasible by passing the schema and the identifier as two arguments using the method explained in answer 1-b.
Everything in one example
Since here we want to pass multiple identifiers and specify their schema, two separators are needed.
CREATE PROCEDURE sp_MultiArgsWithSchema
#Param1 NVARCHAR(MAX)
AS
SELECT #Param1 = REPLACE(REPLACE(#Param1, '[', ''), ']', '')
--Here I'm using a XML split, but feel free to use any string split function you already have.
DECLARE #xml AS XML,
#ArgSeparator AS VARCHAR(2),
#SchemaSeparor AS VARCHAR(1)
SELECT #ArgSeparator = '##',
#SchemaSeparor = '#',
#xml = CAST('<X>'+ (REPLACE(#Param1,#ArgSeparator, '</X><X>') +'</X>') AS XML)
IF OBJECT_ID('tempdb..#QualifiedIdentifiers') IS NOT NULL
DROP TABLE #QualifiedIdentifiers;
--While splitting, we are putting back the dot instead of '#' between schema and name of object
SELECT QualifiedIdentifier = REPLACE(N.value('.', 'VARCHAR(200)'), #SchemaSeparor, '.')
INTO #QualifiedIdentifiers
FROM #xml.nodes('X') as T(N)
SELECT * FROM #QualifiedIdentifiers
--From here, use what is inside #QualifiedIdentifiers and Dynamic SQL if need to achieve what is needed
DECLARE #QualifiedIdentifier NVARCHAR(500)
WHILE EXISTS(SELECT TOP 1 1 FROM #QualifiedIdentifiers)
BEGIN
SELECT TOP 1 #QualifiedIdentifier = QualifiedIdentifier
FROM #QualifiedIdentifiers
SELECT *
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#QualifiedIdentifier)
DELETE TOP (1)
FROM #QualifiedIdentifiers
WHERE QualifiedIdentifier = #QualifiedIdentifier
END
Usage (note that specifying the schema isn't mandatory) :
So, since it is inconvenient to have to double the splitting character, it would be best if schema could be guessed like stated above.
Here is a long shot to pass multi-part identifier without wrapping it with quotes.
Solution:
The query shortcuts is going to create a synonym in the database with a specific name and a DDLTrigger to intercept this specific synonym creation.
Setup up the following shortcut in Query ShortCuts. (Make sure you include last space)
DECLARE #CreateTriggerSQL NVARCHAR(MAX) = 'CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM AS BEGIN DECLARE #EventData XML = EVENTDATA(), #SynonymName NVARCHAR(255), #DbName NVARCHAR(255), #SchemaName NVARCHAR(255), #ObjectName NVARCHAR(255), #Alias NVARCHAR(255) SELECT #SynonymName = #EventData.value(''(/EVENT_INSTANCE/ObjectName)[1]'', ''NVARCHAR(255)'') IF(#SynonymName = ''QueryShortcutX'') BEGIN DROP SYNONYM QueryShortcutX DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE SELECT #DbName = #EventData.value(''(/EVENT_INSTANCE/DatabaseName)[1]'', ''NVARCHAR(255)''), #SchemaName = #EventData.value(''(/EVENT_INSTANCE/TargetSchemaName)[1]'', ''NVARCHAR(255)''), #ObjectName = #EventData.value(''(/EVENT_INSTANCE/TargetObjectName)[1]'', ''NVARCHAR(255)''), #Alias = (CASE WHEN LEN(#SchemaName) > 0 THEN #SchemaName + ''.'' ELSE '''' END) + #ObjectName /*EXEC yourStoredProcHere #Param = #Alias*/ SELECT DbName = #DbName, SchemaName = #SchemaName, ObjectName = #ObjectName, Alias = #Alias, ObjectId = OBJECT_ID(#Alias) END END' EXEC sp_executeSQL #CreateTriggerSQL CREATE SYNONYM QueryShortcutX FOR
As #Vladimir suggested, here we use "sp_executesql" to be able to create the trigger and the synonym at the same time.
Here is the code of the trigger without being inlined.
CREATE TRIGGER DDLTrigger_QueryShortcutX ON DATABASE FOR CREATE_SYNONYM
AS
BEGIN
DECLARE #EventData XML = EVENTDATA(),
#SynonymName NVARCHAR(255),
#DbName NVARCHAR(255),
#SchemaName NVARCHAR(255),
#ObjectName NVARCHAR(255),
#Alias NVARCHAR(255)
SELECT #SynonymName = #EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(255)')
--Safety in case someone else really create a synonym meanwhile.
IF(#SynonymName = 'QueryShortcutX')
BEGIN
--2. Clean up what we created
DROP SYNONYM QueryShortcutX
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
--3. Parsing identifier code here
SELECT #DbName = #EventData.value('(/EVENT_INSTANCE/DatabaseName)[1]', 'NVARCHAR(255)'),
#SchemaName = #EventData.value('(/EVENT_INSTANCE/TargetSchemaName)[1]', 'NVARCHAR(255)'),
#ObjectName = #EventData.value('(/EVENT_INSTANCE/TargetObjectName)[1]', 'NVARCHAR(255)'),
#Alias = (CASE WHEN LEN(#SchemaName) > 0 THEN #SchemaName + '.' ELSE '' END) + #ObjectName
--4. Here, write any print/select statement you want.
--For maintenance, it would be easier to just call a stored procedure from here with parameter and put the desired print/select there.
--Thus avoiding to redo inlining the whole trigger each time.
--EXEC yourStoredProcHere #Param = #Alias
SELECT DbName = #DbName,
SchemaName = #SchemaName,
ObjectName = #ObjectName,
Alias = #Alias,
ObjectId = OBJECT_ID(#Alias)
END
END
Here is the code of the shortcut without being inlined.
DECLARE #CreateTriggerSQL NVARCHAR(MAX) = 'Trigger creation code here...'
IF EXISTS(SELECT TOP 1 1 FROM sys.triggers WHERE name = 'DDLTrigger_QueryShortcutX')
BEGIN
DROP TRIGGER DDLTrigger_QueryShortcutX ON DATABASE
END
EXEC sp_executeSQL #CreateTriggerSQL
IF EXISTS(SELECT TOP 1 1 FROM sys.synonyms WHERE name = 'QueryShortcutX')
BEGIN
DROP SYNONYM QueryShortcutX
END
CREATE SYNONYM QueryShortcutX FOR
The trigger drop itself and the synonym to avoid schema pollution.
The trigger parse the information to retrieve identifier.
Use the identifier for your needs. (use dynamic SQL if needed)
Results for each test item
1.RealColumnName
2.WhatEverText
3.dbo.tests
4.[No selection]
5.dbo.tests.very.much
DbName SchemaName ObjectName Alias ObjectId
1.TEST RealColumnName RealColumnName NULL --FN OBJECT_ID doesn't return value with only column name
2.TEST WhatEverText WhatEverText NULL
3.TEST dbo tests dbo.tests 245575913
4.Incorrect syntax near 'FOR'.
5.TEST very much very.much NULL
The parsing I've made doesn't handle identifier with more than two multipart properly. If you want to improve it. The following XML show you which tag to use.
<TargetServerName>dbo</TargetServerName>
<TargetDatabaseName>tests</TargetDatabaseName>
<TargetSchemaName>very</TargetSchemaName>
<TargetObjectName>much</TargetObjectName>
Note:
If you prefer, you can let the trigger stay permanently within the database.
Also, if you want to pass multiple identifiers, string parsing like I do in my other answer is still a possibility here.
To use this solution, user will have to have "create synonym permission" and either own the schema or have "ALTER SCHEMA permission".

Conversion failed when converting the nvarchar value ... to data type int

I created the procedure listed below:
CREATE procedure getdata
(
#ID int,
#frm varchar(250),
#to varchar(250)
)
AS
BEGIN
DECLARE #SQL nvarchar(500)
set #SQL = 'select'
set #SQL = #SQL + ' EmpName, Address, Salary from Emp_Tb where 1=1 '
IF (#ID <> '' and #ID is not null)
Begin
SET #sql=#sql+' AND Emp_Id_Pk=' +#ID
End
END
print #sql
--execute (#sql)
I try to execute it using:
**execute getdata 3,'','';**
But I'm getting the following error:
Conversion failed when converting the nvarchar value 'select EmpName,
Address, Salary from Emp_Tb where 1=1 AND Emp_Id_Pk=' to data type int
Please help.
You are trying to concatenate a string and an integer.
You need to cast #ID as a string.
try:
SET #sql=#sql+' AND Emp_Id_Pk=' + CAST(#ID AS NVARCHAR(10))
Try Using
CONVERT(nvarchar(10),#ID)
This is similar to cast but is less expensive(in terms of time consumed)
I was using a KEY word for one of my columns and I solved it with brackets []
I use the latest version of SSMS or sql server management studio. I have a SQL script (in query editor) which has about 100 lines of code. This is error I got in the query:
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the nvarchar value 'abcd' to data type int.
Solution - I had seen this kind of error before when I forgot to enclose a number (in varchar column) in single quotes.
As an aside, the error message is misleading. The actual error on line number 70 in the query editor and not line 2 as the error says!
don't use string concatenation to produce sql, you can use sp_executesql system stored prcedure to execute sql statement with parameters
create procedure getdata #ID int, #frm varchar(250), #to varchar(250) as
begin
declare #sql nvarchar(max), #paramDefs nvarchar(max);
set nocount on;
set #sql = N'select EmpName, Address, Salary from Emp_Tb where #id is null or Emp_Id_Pk = #id';
set #paramDefs = N'#id int';
execute sp_executesql #sql, #paramDefs, #id = #ID;
end
see sp_executesql
I got this error when I used a where clause which looked at a nvarchar field but didn't use single quotes.
My invalid SQL query looked like this:
SELECT * FROM RandomTable WHERE Id IN (SELECT Id FROM RandomTable WHERE [Number] = 13028533)
This didn't work since the Number column had the data type nvarchar. It wasn't an int as I first thought.
I changed it to:
SELECT * FROM RandomTable WHERE Id IN (SELECT Id FROM RandomTable WHERE [Number] = '13028533')
And it worked.
You got this Error because you tried to convert column DataType from String to int which is
leagal if and only if
you dont have row in that table with string content inside that column
so just make sure your previously inserted Rows is compatible with the new changes
I have faced to the same problem, i deleted the constraint for the column in question and it worked for me. You can check the folder Constraints.
Capture :
You must use CONCAT and not the +
SET #sql = CONCAT(#sql,' AND Emp_Id_Pk=' ,#ID )

Return multiple columns as single comma separated row in SQL Server 2005

I'm curious to see if this is possible.
I have a table or this could be specific to any old table with data. A simple SELECT will return the columns and rows as a result set. What I'm trying to find out if is possible to return rows but rather than columns, the columns concatenated and are comma separated. So expected amount of rows returned but only one varchar column holding comma separated results of all the columns just like a CSV file.
Thanks.
[UPDATE]
Here is a bit more detail why I'm asking. I don't have the option to do this on the client, this is a task I'm trying to do with SSIS.
Scenario: I have a table that is dynamically created in SSIS but the column names change each time it's built. The original package uses BCP to grab the data and put it into a flat file but due to permissions when run as a job BCP can't create the flat file at the required destination. We can't get this changed either.
The other issue is that with SSIS 2005, using the flat files destination, you have to map the column name from the input source which I can't do because the column names keep changing.
I've written a script task to grab all the data from the original tables and then use stream writer to write to the CSV but I have to loop through each row then through each column to produce the string built up of all the columns. I want to measure performance of this concatenation of columns on sql server against a nasty loop with vb.net.
If I can get sql to produce a single column for each row I can just write a single line to the text file instead of iterating though each column to build the row.
I Think You Should try This
SELECT UserName +','+ Password AS ColumnZ
FROM UserTable
Assuming you know what columns the table has, and you don't want to do something dynamic and crazy, you can do this
SELECT CONCAT(ColumnA, ',', ColumnB) AS ColumnZ
FROM Table
There is a fancy way to this using SQL Server's XML functions, but for starters could you just cast the contents of the columns you care about as varchar and concatenate them with commas?
SELECT cast(colA as varchar)+', '+cast(colB as varchar)+', '+cast(colC as varchar)
FROM table
Note, that this will get tripped up if any of your contents have a comma or double quotes in them, in which case you can also use a replace function on each cast to escape them.
This could stand to be cleaned up some, but you can do this by using the metadata stored in sys.objects and sys.columns along with dynamic SQL. Note that I am NOT a fan of dynamic SQL, but for reporting purposes it shouldn't be too much of a problem.
Some SQL to create test data:
if (object_id('test') is not null)
drop table test;
create table test
(
id uniqueidentifier not null default newId()
,col0 nvarchar(255)
,col1 nvarchar(255)
,col2 nvarchar(255)
,col3 nvarchar(255)
,col4 nvarchar(255)
);
insert into test (col0,col1,col2,col3,col4)
select 'alice','bob','charlie','dave','emily'
union
select 'abby','bill','charlotte','daniel','evan'
A stored proc to build CSV rows:
-- emit the contents of a table as a CSV.
-- #table_name: name of a permanent (in sys.objects) table
-- #debug: set to 1 to print the generated query
create procedure emit_csv(#table_name nvarchar(max), #debug bit = 0)
as
declare #object_id int;
set nocount on;
set #object_id = object_id(#table_name);
declare #name nvarchar(max);
declare db_cursor cursor for
select name
from sys.columns
where object_id = #object_id;
open db_cursor;
fetch next from db_cursor into #name
declare #query nvarchar(max);
set #query = '';
while ##FETCH_STATUS = 0
begin
-- TODO: modify appended clause to escape commas in addition to trimming
set #query = #query + 'rtrim(cast('+#name+' as nvarchar(max)))'
fetch next from db_cursor into #name;
-- add concatenation to the end of the query.
-- TODO: Rearrange #query construction order to make this unnecessary
if (##fetch_status = 0)
set #query = #query + ' + '','' +'
end;
close db_cursor;
deallocate db_cursor;
set #query = 'select rtrim('+#query+') as csvrow from '+#table_name;
if #debug != 0
begin
declare #newline nvarchar(2);
set #newline = char(13) + char(10)
print 'Generated SQL:' + #newline + #query + #newline + #newline;
end
exec (#query);
For my test table, this generates the query:
select
rtrim(rtrim(cast(id as nvarchar(max)))
+ ','
+rtrim(cast(col0 as nvarchar(max)))
+ ','
+rtrim(cast(col1 as nvarchar(max)))
+ ','
+rtrim(cast(col2 as nvarchar(max)))
+ ','
+rtrim(cast(col3 as nvarchar(max)))
+ ','
+rtrim(cast(col4 as nvarchar(max))))
as csvrow
from test
and the result set:
csvrow
-------------------------------------------------------------------------------------------
EEE16C3A-036E-4524-A8B8-7CCD2E575519,alice,bob,charlie,dave,emily
F1EE6C84-D6D9-4621-97E6-AA8716C0643B,abby,bill,charlotte,daniel,evan
Suggestions
Modify the cursor loop to escape commas
Make sure that #table_name refers to a valid table (if object_id(#table_name) is null) in the sproc
Some exception handling would be good
Set permissions on this so that only the account that runs the report can execute it. String concatenation in dynamic SQL can be a big security hole, but I don't see another way to do this.
Some error handling to ensure that the cursor gets closed and deallocated might be nice.
This can be used for any table that is not a #temp table. In that case, you'd have to use sys.objects and sys.columns from tempdb...
select STUFF((select ','+ convert(varchar,l.Subject) from tbl_Student B,tbl_StudentMarks L
where B.Id=L.Id FOR XML PATH('')),1,1,'') Subject FROM tbl_Student A where A.Id=10

Dynamically search columns for given table

I need to create a search for a java app I'm building where users can search through a SQL database based on the table they're currently viewing and a search term they provide. At first I was going to do something simple like this:
SELECT * FROM <table name> WHERE CAST((SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table name>')
AS VARCHAR) LIKE '%<search term>%'
but that subquery returns more than one result, so then I tried to make a procedure to loop through all the columns in a given table and put any relevant fields in a results table, like this:
CREATE PROC sp_search
#tblname VARCHAR(4000),
#term VARCHAR(4000)
AS
SET nocount on
SELECT COLUMN_NAME
INTO #tempcolumns
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tblname
ALTER TABLE #tempcolumns
ADD printed BIT,
num SMALLINT IDENTITY
UPDATE #tempcolumns
SET printed = 0
DECLARE #colname VARCHAR(4000),
#num SMALLINT
WHILE EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0)
BEGIN
SELECT #num = MIN(num)
FROM #tempcolumns
WHERE printed = 0
SELECT #colname = COLUMN_NAME
FROM #tempcolumns
WHERE num = #num
SELECT * INTO #results FROM #tblname WHERE CAST(#colname AS VARCHAR)
LIKE '%' + #term + '%' --this is where I'm having trouble
UPDATE #tempcolumns
SET printed = 1
WHERE #num = num
END
SELECT * FROM #results
GO
This has two problems: first is that it gets stuck in an infinite loop somehow, and second I can't select anything from #tblname. I tried using dynamic sql as well, but I don't know how to get results from that or if that's even possible.
This is for an assignment I'm doing at college and I've gotten this far after hours of trying to figure it out. Is there any way to do what I want to do?
You need to only search columns that actually contain strings, not all columns in a table (which may include integers, dates, GUIDs, etc).
You shouldn't need a #temp table (and certainly not a ##temp table) at all.
You need to use dynamic SQL (though I'm not sure if this has been part of your curriculum so far).
I find it beneficial to follow a few simple conventions, all of which you've violated:
use PROCEDURE not PROC - it's not a "prock," it's a "stored procedure."
use dbo. (or alternate schema) prefix when referencing any object.
wrap your procedure body in BEGIN/END.
use vowels liberally. Are you saving that many keystrokes, never mind time, saying #tblname instead of #tablename or #table_name? I'm not fighting for a specific convention but saving characters at the cost of readability lost its charm in the 70s.
don't use the sp_ prefix for stored procedures - this prefix has special meaning in SQL Server. Name the procedure for what it does. It doesn't need a prefix, just like we know they're tables even without a tbl prefix. If you really need a prefix there, use another one like usp_ or proc_ but I personally don't feel that prefix gives you any information you don't already have.
since tables are stored using Unicode (and some of your columns might be too), your parameters should be NVARCHAR, not VARCHAR. And identifiers are capped at 128 characters, so there is no reason to support > 257 characters for #tablename.
terminate statements with semi-colons.
use the catalog views instead of INFORMATION_SCHEMA - though the latter is what your professor may have taught and might expect.
CREATE PROCEDURE dbo.SearchTable
#tablename NVARCHAR(257),
#term NVARCHAR(4000)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT * FROM ' + #tablename + ' WHERE 1 = 0';
SELECT #sql = #sql + '
OR ' + c.name + ' LIKE ''%' + REPLACE(#term, '''', '''''') + '%'''
FROM
sys.all_columns AS c
INNER JOIN
sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE
c.[object_id] = OBJECT_ID(#tablename)
AND t.name IN (N'sysname', N'char', N'nchar',
N'varchar', N'nvarchar', N'text', N'ntext');
PRINT #sql;
-- EXEC sp_executesql #sql;
END
GO
When you're happy that it's outputting the SELECT query you're after, comment out the PRINT and uncomment the EXEC.
You get into an infinite loop because EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0) will always return a row even if there are no matches - you need to EXISTS (SELECT * .... instead
To use dynamic SQL, you need to build up a string (varchar) of the SQL statement you want to run, then you call it with EXEC
eg:
declare #s varchar(max)
select #s = 'SELECT * FROM mytable '
Exec (#s)