An expression of non-boolean type specified in a context where a condition is expected, near 'tblProje' - tsql

I am getting this error message when running this sql statement in ssms:
An expression of non-boolean type specified in a context where a condition is expected, near 'tblProje'
This is the statement itself:
PRINT 'Updating FileSetId data from Table Project to Table tblProject'
DECLARE #SQL NVARCHAR(100)
SET #SQL = 'UPDATE tblProject set tblProject.ProjectFileSetId = Project.FileSetId
FROM Project
WHERE tblProject.AccountingProject = Project.Project_Id'
IF EXISTS(select * from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Project' AND COLUMN_NAME = 'FileSetId')
BEGIN
execute sp_executesql #SQL
END
GO
I am trying to make the statement so that it can run as many times as possible. Basically checking to make sure that a column exists before trying to update from it. I cannot tell where this error is coming from

If you take your query and look at the length, you will see an issue:
DECLARE #SQL NVARCHAR(100)
SET #SQL = 'UPDATE tblProject set tblProject.ProjectFileSetId = Project.FileSetId
FROM Project
WHERE tblProject.AccountingProject = Project.Project_Id'
select len(#sql)
select len('UPDATE tblProject set tblProject.ProjectFileSetId = Project.FileSetId
FROM Project
WHERE tblProject.AccountingProject = Project.Project_Id')
Your variable assignment is cutting off 41 chars at the end so it is not valid SQL to execute when you run sp_executesql. Change your variable to something like NVARCHAR(4000) or NVARCHAR(MAX) and it will work.
PRINT 'Updating FileSetId data from Table Project to Table tblProject'
DECLARE #SQL NVARCHAR(MAX)
SET #SQL = 'UPDATE tblProject set tblProject.ProjectFileSetId = Project.FileSetId
FROM Project
WHERE tblProject.AccountingProject = Project.Project_Id'
IF EXISTS(select * from INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Project' AND COLUMN_NAME = 'FileSetId')
BEGIN
execute sp_executesql #SQL
END
GO

Related

Enabling or disabling part of TSQL select statement (columns)

Let's say I have a table with five columns. Full select statement would be :
Select col1, col2, col3, col4, col5
from tbl
But I need this query to be "dynamic", every column must be possible to enable/disable. So, as far as I understand I need five tags (bool let's say).
If i have tag1=0, tag2=1, tag3=1, tag4=0, tag5 =0 then the select statement should be like this:
Select col2, col3
from tbl
If i have tag1=1, tag2=0, tag3=0, tag4=0, tag5 =0 then the select statement should be like this:
Select col1
from tbl
So is there a possibility to do so in TSQL? I intend to create SP and execute it from php.
P.s. I understand that there's a solution to make a bunch of IF statements with all possible tag1...tag5 variations, but this is not very effective when the number of columns (and enable tags) is high.
create procedure GetTblList
#Tag1 bit,
#Tag2 bit,
#Tag3 bit,
#Tag4 bit,
#Tag5 bit
as
declare #SQL nvarchar(max)
set #SQL = 'select '
if #Tag1 = 1 set #SQL = #SQL + 'Col1,'
if #Tag2 = 1 set #SQL = #SQL + 'Col2,'
if #Tag3 = 1 set #SQL = #SQL + 'Col3,'
if #Tag4 = 1 set #SQL = #SQL + 'Col4,'
if #Tag5 = 1 set #SQL = #SQL + 'Col5,'
if #SQL = 'select ' set #SQL = #SQL + 'null as NoColumnSelected'
set #SQL = stuff(#SQL, len(#SQL), 1, ' from TbL')
exec (#SQL)
Even tough it is not a recommended practice the only possible way seems to be creating the sql statement as a string and executing it.
If you build the sql statement string in your application layer you can send it to db layer for execution as a single string. This one should be clear.
On the other hand if you want build the sql statement string at DB level (in an SP for example) you can use sp_executesql stored procedure to execute it. Sample:
DECLARE #sql nvarchar(MAX);
SET #sql = 'SELECT col1'
IF #tag1 = 1 SET #sql = #sql + ', dynamic_col_1';
IF #tag2 = 1 SET #sql = #sql + ', dynamic_col_2';
IF #tag3 = 1 SET #sql = #sql + ', dynamic_col_3';
SET #sql = #sql + ' FROM myTable'
EXEC sp_executesql #sql;
Either case you need to send all your tags as parameters or you can aggregate them into a single 5 digit string parameter where each digit represents a flag.

Is there a better way to programatically access tables using SQL

Using MS SQL2000 at present if that makes any difference.
Is there a better way than the method below to be able to programatically access a table ?
declare #tableName as varchar(50)
declare #sql varchar(4000)
set #tableName = 'User'
print #tableName
If EXISTS(
select TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE table_name = ''+#TableName+''
)
BEGIN
set #sql = 'select * from [' + #tableName + ']'
exec(#sql)
end
Essentially Im trying to create a simple Mapping tool for CRUD operations so that I need only one Sproc for each operation, and I can pass in my parameterised object, a table name and let the database do the rest. This is purely for my own personal education, hence why Im not using an established framework, so if there are any major gotcha's with my idea or the code above, I'd appreciate knowing as well.
Thanks
This is complete example to create a SP by follow your initial code:
CREATE PROCEDURE dbo.CustomSelect (#tableName as varchar(50))
AS
SET NOCOUNT ON
DECLARE #sql varchar(4000)
If EXISTS(
select TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE table_name = #tableName
)
BEGIN
set #sql = 'select 1 as Found, * from [' + #tableName + ']'
exec(#sql)
END
ELSE
BEGIN
select 0 as Found
END
This SP always return a recordset so you can check the value of the field FOUND to know if the table exist or not
usage:
EXEC CustomSelect 'User'
Hope it helps

How to get row count from EXEC() in a TSQL SPROC?

I have a TSQL sproc that builds a query as and executes it as follows:
EXEC (#sqlTop + #sqlBody + #sqlBottom)
#sqlTop contains something like SELECT TOP(x) col1, col2, col3...
TOP(x) will limit the rows returned, so later I want to know what the actual number of rows in the table is that match the query.
I then replace #sqlTop with something like:
EXEC ('SELECT #ActualNumberOfResults = COUNT(*) ' + #sqlBody)
I can see why this is not working, and why a value not declared error occurs, but I think it adequately describes what I'm trying to accomplish.
Any ideas?
use sp_executesql and an output parameter
example
DECLARE #sqlBody VARCHAR(500),#TableCount INT, #SQL NVARCHAR(1000)
SELECT #sqlBody = 'from sysobjects'
SELECT #SQL = N'SELECT #TableCount = COUNT(*) ' + #sqlBody
EXEC sp_executesql #SQL, N'#TableCount INT OUTPUT', #TableCount OUTPUT
SELECT #TableCount
GO
You could instead have the dynamic query return the result as a row set, which you would then insert into a table variable (could be a temporary or ordinary table as well) using the INSERT ... EXEC syntax. Afterwards you can just read the saved value into a variable using SELECT #var = ...:
DECLARE #rowcount TABLE (Value int);
INSERT INTO #rowcount
EXEC('SELECT COUNT(*) ' + #sqlBody);
SELECT #ActualNumberOfResults = Value FROM #rowcount;
Late in the day, but I found this method much simpler:
-- test setup
DECLARE #sqlBody nvarchar(max) = N'SELECT MyField FROM dbo.MyTable WHERE MyOtherField = ''x''';
DECLARE #ActualNumberOfResults int;
-- the goods
EXEC sp_executesql #sqlBody;
SET #ActualNumberOfResults = ##ROWCOUNT;
SELECT #ActualNumberOfResults;
After executing your actual query store the result of ##ROWCOUNT in any variable which you can use later.
EXEC sp_executesql 'SELECT TOP 10 FROM ABX'
SET #TotRecord = ##ROWCOUNT into your variable for later use.
Keep in mind that dynamic SQL has its own scope. Any variable declared/modified there will go out of scope after your EXEC or your sp_executesql.
Suggest writing to a temp table, which will be in scope to your dynamic SQL statement, and outside.
Perhaps put it in your sqlBottom:
CREATE TABLE ##tempCounter(MyNum int);
EXEC('SELECT #ActualNumberOfResults = COUNT(*) ' + #sqlBody +
'; INSERT INTO ##tempCounter(MyNum) VALUES(#ActualNumberOfResults);');
SELECT MyNum FROM ##tempCounter;
You can use output variable in SP_EXECUTESQL
DECLARE #SQL NVARCHAR(MAX);
DECLARE #ParamDefinition NVARCHAR(100) = '#ROW_SQL INT OUTPUT'
DECLARE #AFFECTED_ROWS INT;
SELECT
#SQL = N'SELECT 1 UNION ALL SELECT 2'
SELECT #SQL += 'SELECT #ROW_SQL = ##ROWCOUNT;';
EXEC SP_EXECUTESQL #SQL, #ParamDefinition, #ROW_SQL=#AFFECTED_ROWS OUTPUT;
PRINT 'Number of affected rows: ' + CAST(#AFFECTED_ROWS AS VARCHAR(20));
Ouput:
SQL2.sql: Number of affected rows: 2
Thanks Jesus Fernandez!
The only problem with the answers that create temporary tables (either using "DECLARE #rowcount TABLE" or "CREATE TABLE ##tempCounter(MyNum int)") is that you're having to read all the affected records off disk into memory. If you're expecting a large number of records this may take some time.
So if the answer is likely to be large the "use sp_executesql and an output parameter" solution is a more efficient answer. And it does appear to work.

Getting error while export data from excel

I am getting following error
ERROR:- Incorrect syntax near '+'.
while executing following T-Sql
DECLARE #DatabasePath VARCHAR(MAX)
SET #DatabasePath = 'E:\ABC.xls'
INSERT INTO [dbo].[Table_1]
SELECT *
FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0',
'Excel 8.0;Database='+#DatabasePath+'',
'SELECT * FROM [Sheet1$]') AS xlsTable
Is there something wrong in T-Sql.
Actually i want to create a stored procedure where i will pass excel sheet path in #DatabasePath input parameter.
I dont thing this will work for you.
From OPENROWSET (Transact-SQL)
'datasource'
Is a string constant that corresponds
to a particular OLE DB data source.
Have you tried something like
DECLARE #DatabasePath VARCHAR(MAX)
SET #DatabasePath = 'C:\tada.xlsx'
DECLARE #RowSetString VARCHAR(MAX)
SELECT #RowSetString = 'SELECT * FROM OPENROWSET(''Microsoft.Jet.OLEDB.4.0'',''Excel 8.0;Database=' + #DatabasePath + ''',''SELECT * FROM [Sheet1$]'')'
SELECT #RowSetString
EXEC(#RowSetString)
You will need to use dynamic SQL:
DECLARE #DatabasePath VARCHAR(MAX)
SET #DatabasePath = 'E:\ABC.xls'
DECLARE #sql nvarchar(MAX)
SET #sql = '
INSERT INTO [dbo].[Table_1]
SELECT *
FROM OPENROWSET(''Microsoft.Jet.OLEDB.4.0'',
''Excel 8.0;Database=' + #DatabasePath + ',
''SELECT * FROM [Sheet1$]'') AS xlsTable'
EXEC sp_executesql #sql

How to handle an empty result set from an OpenQuery call to linked analysis server in dynamic SQL?

I have a number of stored procedures structured similarly to this:
DECLARE #sql NVARCHAR(MAX)
DECLARE #mdx NVARCHAR(MAX)
CREATE table #result
(
[col1] NVARCHAR(50),
[col2] INT,
[col3] INT
)
SET #mdx = '{some dynamic MDX}'
SET #sql = 'SELECT a.* FROM OpenQuery(LinkedAnalysisServer, ''' + #mdx + ''') AS a'
INSERT INTO #result
EXEC sp_executesql #sql
SELECT * FROM #result
This works quite well when results exist in the cube. However, when the OpenQuery results are empty, the INSERT fails with this error:
Column name or number of supplied
values does not match table
definition.
My question is, what is the best way to handle this scenario? I'm using the results in a static report file (.rdlc), so the explicit typing of the temp table is (I'm pretty sure) required.
Use TRY/CATCH in your stored procedure, you'll notice there is a specific error number for your problem, so check the error number and if it is that, return an empty result set. As you already have the table defined that'll be easier.
PseudoCode looks something like this:
SET #mdx = '{some dynamic MDX}'
SET #sql = 'SELECT a.* FROM OpenQuery(LinkedAnalysisServer, ''' + #mdx + ''') AS a'
BEGIN TRY
INSERT INTO #result
EXEC sp_executesql #sql
END TRY
BEGIN CATCH
IF ERROR_NUMBER <> 'The error number you are seeing'
BEGIN
RAISERROR('Something happened that was not an empty result set')
END
END CATCH
SELECT * FROM #result
You'll want to check for that particular error, so that you don't just return empty result sets if your SSAS server crashes for example.
There is another solution to this issue, similar to the accepted answer, which involves using an IF statement instead of TRY...CATCH.
http://www.triballabs.net/2011/11/overcoming-openquery-mdx-challenges/
IF (SELECT COUNT(*)
FROM OPENQUERY("SSAS1",
'SELECT [Measures].[Target Places] ON COLUMNS
FROM [ebs4BI_FactEnrolment]
WHERE [DimFundingYear].[Funding Year].&[17]')) > 0
EXEC sp_executesql N'SELECT CONVERT(varchar(20),
"[DimPAPSCourse].[Prog Area].[Prog Area].[MEMBER_CAPTION]")
as ProgArea,
convert(float, "[Measures].[Target Places]") as Target
FROM OPENQUERY("SSAS1",
''SELECT [Measures].[Target Places] ON COLUMNS,
[DimPAPSCourse].[Prog Area].[Prog Area] ON ROWS
FROM [ebs4BI_FactEnrolment]
WHERE [DimFundingYear].[Funding Year].&[17]'')'
ELSE
SELECT '' as ProgArea, 0 as Target
WHERE 1=0