I have a simple table:
CREATE TABLE [dbo].[test]
(
[eins] [varchar](50) NOT NULL,
[zwei] [varchar](50) NULL,
CONSTRAINT [PK_test]
PRIMARY KEY CLUSTERED ([eins] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
with two columns eins und zwei, both varchar(50)
with the values
insert into test(eins, zwei) values(1,2)
1 and 2 in the corresponding columns.
The query
select eins from test
gives the correct result of 1
the following code also gives the correct result of 1 in the results window:
declare
#in varchar(50),
#sql nvarchar(500)
set #in = 'eins'
set #sql = 'select ' + #in + ' from test'
Exec(#sql)
However, it doesn't make use of an output parameter and I need the result for further processing.
So, I try:
exec sp_executesql N' Select #1 from test where zwei = #2',N'#1 nvarchar(100),#2 nvarchar(100)',#1=N'eins',#2=N'2'
with an expected result of 1. However: the result is eins, i.e., the column name, not the value.
How can I query for something like Select #Variable from #Variable2 where #variabel3 = #Variable4?
The table and columns can be non-variable, if need be, what's primarily important is, the Select #Variable. I need this value for further processing.
Try something like this
DECLARE #result int
exec sp_executesql
N'Select #1=eins from test where zwei = #2',
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
What that does is say that the #1 is an OUTPUT variable inside the EXECed query string. Then it binds #result to the #1, so you can retrieve it. I've never found OUTPUT parameters very intuitive to use.
The Code from DWright in the last post has the correct result, but the main problem isn't solved.
I dont know the name of the column while writing the code. The following code seems to be correct:
Declare #result int
Declare #sql nvarchar(500)
Declare #columnname nvarchar(50)
set #columnname = 'eins'
set #sql= N'Select #1= ' + #columnname +' from test1 where zwei = #2'
exec sp_executesql
#sql,
N'#1 nvarchar(100) OUTPUT,#2 nvarchar(100)',
#1=#result OUTPUT,#2=N'2'
SELECT #result
And the result is the expectet 1
Thank you for helping
Related
I would like to create an index and making its options (with) as configurable, example I will take sort_IN_TempDB
DECLARE #On NUMERIC(10,2) = 1
CREATE NONCLUSTERED INDEX NCI_TN
ON Table_Name (Student_ID)
WITH (SORT_IN_TEMPDB = #On)
But it throws an error and says the excepted value is Numeric, Integer, ON, or OFF. Is it possible to make options value from variable?
In SQL Server DDL cannot be parameterized, and in statements that can be parameterized, object identifiers and keywords can't be parameterized.
You'll need to use dynamic SQL, eg
DECLARE #On NUMERIC(10,2) = 1
declare #sql nvarchar(max) = concat( N'
CREATE NONCLUSTERED INDEX NCI_TN
ON Table_Name (Student_ID)
WITH (SORT_IN_TEMPDB = ', case when #On = 1 then 'ON' else 'OFF' end,')')
print #sql
exec (#sql)
without dynamic SQL you can use something like
DECLARE #On NUMERIC(10,2) = 1
if #On =1
begin
CREATE NONCLUSTERED INDEX NCI_TN
ON Table_Name (Student_ID)
WITH (SORT_IN_TEMPDB = ON)
end
else
begin
CREATE NONCLUSTERED INDEX NCI_TN
ON Table_Name (Student_ID)
WITH (SORT_IN_TEMPDB = OFF)
end
Hi I need to create a view or stored procedure that combines data and returns a result set from 3 different databases on the same server using a column that holds a schema (db) name.
For Example on the first DB I have this table:
CREATE TABLE [dbo].[CloudUsers](
ID int IDENTITY(1,1) NOT NULL,
Username nvarchar(50) NULL,
MainDB nvarchar(100) NULL
) ON [PRIMARY]
Each CloudUser has a separate DB so next now I need to fetch the data from the User database using the MainDB name. The data I need is always 1 row cause I'm using aggregate functions / query.
So in the User MainDB let's say I have this table.
CREATE TABLE [dbo].[CLIENT](
ID int NOT NULL,
Name nvarchar(50) NULL,
ProjectDBName [nvarchar](100) NULL
CreationDate datetime NULL
) ON [PRIMARY]
And I query like:
select min(CreationDate) from MainDB.Client
The same Idea for the Client I need to fetch even more data from a 3rd database that points to the Client ProjectDBName. Again it's aggregate data:
select Count(id) as TotalTransactions from ProjectDBName.Journal
My final result should have records from all databases. It's readonly data that I need for statistics.
Final result set example:
CloudUsers.Username, MainDB->CreationDate, ProjectDBName->TotalTransaction
How can I achieve that ?
This is not easy - and without a schema and sample data, I can't give you a precise answer.
You need to iterate through each client, and use dynamic SQL to execute a the query against the mainDB and projectDB join. You can either do that in one gigantic "union" query, or by creating a temporary table and inserting the data into that temporary table, and then selecting from the temp table at the end of the query.
For you who are curious of how to solve this issue I have found my own solution using some cursors + dynamic and a simple table variable, enjoy.
ALTER PROCEDURE CloudAnalysis as
DECLARE #objcursor cursor
DECLARE #innercursor cursor
DECLARE #userid int
,#maindb nvarchar(100)
,#clientid int
,#name nvarchar(50)
,#projdb nvarchar(100)
,#stat nvarchar(50)
,#sql nvarchar(max)
,#vsql nvarchar(max)
,#rowcount int
DECLARE #result table(userid int,clientid int,maindb nvarchar(100),name nvarchar(50),projdb nvarchar(100),stat nvarchar(50))
SET #objcursor = CURSOR FORWARD_ONLY STATIC FOR SELECT c.id,c.maindb,u.client_id FROM dbo.ClientUsers c join dbo.UserClients u on c.id = u.user_id open #objcursor
FETCH NEXT FROM #objcursor INTO #userid,#maindb,#clientid
WHILE (##FETCH_STATUS=0)
BEGIN
IF (EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = #maindb
OR name = #maindb)))
BEGIN
set #sql = N'SELECT #name = c.name,#projdb=c.ProjectDBName FROM ' + #maindb + '.dbo.CLIENT c WHERE c.id = ' + cast(#clientid as nvarchar)
EXECUTE sp_executesql #sql, N'#name NVARCHAR(50) OUTPUT,#projdb NVARCHAR(100) OUTPUT',
#name = #name OUTPUT
,#projdb = #projdb OUTPUT
SELECT #rowcount = ##ROWCOUNT
IF #rowcount > 0
BEGIN
--print ' client: ' + cast(#clientid as nvarchar)+
--':' + #name + ' projdb: ' + #projdb
IF (EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = #projdb
OR name = #projdb)))
BEGIN
SET #sql = N'SELECT #stat = j.stat FROM ' + #projdb + '.dbo.JournalTransaction j'
EXECUTE sp_executesql #sql
,N'#stat NVARCHAR(50) OUTPUT'
,#stat = #stat OUTPUT
END
INSERT INTO #result (userid,clientid,maindb,name,projdb,stat)
VALUES (#userid,#clientid,#maindb,#name,#projdb,#stat)
END
END
FETCH NEXT FROM #objcursor INTO #userid,#maindb,#clientid
END
CLOSE #objcursor
DEALLOCATE #objcursor
SELECT * FROM #result
We've been having an issue every few months where all of a sudden a job or procedure will start failing due to a quoted_Identifier issue. The quoted identifier in the proc or even table will change from 1 to 0 and we don't see any recent modified date on that record. We aren't sure how this is happening and because it's so sporadic, I can't reproduce it or trace it easily. Any ideas as to why this is occurring or what I can do to find out. I've done a lot of research without luck so far.
Thanks
You could create a DDL trigger activated by CREATE/ALTER PROCEDURE events. Inside this trigger you could use EVENTDATE function to get information about SQL statements execute including ANSI_NULLS and QUOTED_IDENTIFIER settings.
For example, you could use ddlDatabaseTriggerLog ddl trigger from Adventure Works OLTP database that insert into [dbo].[DatabaseLog] all ddl changes from current database.
DDL Trigger:
CREATE TRIGGER [ddlDatabaseTriggerLog] ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS AS
BEGIN
SET NOCOUNT ON;
SET ANSI_WARNINGS ON;
DECLARE #data XML;
DECLARE #schema sysname;
DECLARE #object sysname;
DECLARE #eventType sysname;
SET #data = EVENTDATA();
SET #eventType = #data.value('(/EVENT_INSTANCE/EventType)[1]', 'sysname');
SET #schema = #data.value('(/EVENT_INSTANCE/SchemaName)[1]', 'sysname');
SET #object = #data.value('(/EVENT_INSTANCE/ObjectName)[1]', 'sysname')
IF #object IS NOT NULL
PRINT ' ' + #eventType + ' - ' + #schema + '.' + #object;
ELSE
PRINT ' ' + #eventType + ' - ' + #schema;
IF #eventType IS NULL
PRINT CONVERT(nvarchar(max), #data);
INSERT [dbo].[DatabaseLog]
(
[PostTime],
[DatabaseUser],
[Event],
[Schema],
[Object],
[TSQL],
[XmlEvent]
)
VALUES
(
GETDATE(),
CONVERT(sysname, CURRENT_USER),
#eventType,
CONVERT(sysname, #schema),
CONVERT(sysname, #object),
#data.value('(/EVENT_INSTANCE/TSQLCommand)[1]', 'nvarchar(max)'),
#data
);
END;
GO
[dbo].[DatabaseLog]
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[DatabaseLog](
[DatabaseLogID] [int] IDENTITY(1,1) NOT NULL,
[PostTime] [datetime] NOT NULL,
[DatabaseUser] [sysname] NOT NULL,
[Event] [sysname] NOT NULL,
[Schema] [sysname] NULL,
[Object] [sysname] NULL,
[TSQL] [nvarchar](max) NOT NULL,
[XmlEvent] [xml] NOT NULL,
CONSTRAINT [PK_DatabaseLog_DatabaseLogID] PRIMARY KEY NONCLUSTERED
(
[DatabaseLogID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
Who/when changed dbo.uspGetEmployeeManagers procedure ?
SELECT *
FROM [dbo].[DatabaseLog] x
WHERE x.[Event] IN ('CREATE_PROCEDURE', 'ALTER_PROCEDURE')
AND x.[Schema] = 'dbo'
AND x.[Object] = 'uspGetEmployeeManagers'
XmlEvent column content:
<EVENT_INSTANCE>
<EventType>CREATE_PROCEDURE</EventType>
...
<TSQLCommand>
<SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON" QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
<CommandText>
CREATE PROCEDURE [dbo].[uspGetEmployeeManagers]
#BusinessEntityID [int]
AS
...
Those scripts are helpful and I'll use them in the future. I figured out what the issue is. A stored procedure had quoted_identifier set to 0 and it had been that way for at least a year. However, someone created a filtered index on a table that the stored procedure was using. They didn't realize that the filtered index required quoted_identifier to be set to 1.
I have this database setup: http://sqlfiddle.com/#!6/3076a/4
EDIT:
CREATE TABLE [dbo].[Sensor1](
[SensorTime] [datetime] NOT NULL,
[SensorValue] [float] NOT NULL,
PRIMARY KEY CLUSTERED
(
[SensorTime] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:10:34.343', 10);
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:20:34.343', 20);
INSERT INTO dbo.Sensor1(SensorTime, SensorValue) VALUES ('2014-03-17 11:30:34.343', 30);
CREATE PROCEDURE [dbo].[SelectLatestByDate]
#name nvarchar(128),
#date datetime
AS
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
SELECT TOP 1 * FROM '+ QUOTENAME(#name) +' WHERE SensorTime <= #date ORDER BY SensorTime DESC
'
EXEC sp_executesql #sql, N'#date datetime', #date = #date
RETURN
Now, whenever a new value will be inserted, I want to make a check to see if it's not equal to the last value. If it's the same, it should not insert the value. Right now I have this stored procedure to do this, but it's slow and I'm wondering if there is a faster way...
CREATE PROCEDURE [dbo].[PutData]
#name nvarchar(128),
#date datetime,
#value float
AS
DECLARE #Table TABLE
(
SensorTime datetime,
SensorValue float
)
INSERT INTO #Table
EXEC dbo.SelectLatestByDate #name, #date
DECLARE #lastValue float
SELECT #lastValue = [#Table].[SensorValue] FROM #Table
IF (#lastValue != #value)
BEGIN
DECLARE #sql NVARCHAR(MAX)
SET #sql = N'
INSERT INTO ' + QUOTENAME(#name) + ' (SensorTime, SensorValue) VALUES (#date, #value)
'
EXEC sp_executesql #sql, N'#date datetime, #value float', #date = #date, #value = #value
END
RETURN 0
The tablename should be variable, that's the reason I made a stored procedure for it
I guess you can use NOT EXIST condition with your INSERT statement to test for the existence of rows.
IF NOT EXISTS ( [subquery] ) INSERT INTO ... VALUES(...)
The document of NOT EXIST is here :
http://technet.microsoft.com/en-us/library/ms188336.aspx
To specify the row which has the the maximum SensorTime, you can use MAX( ) function like below:
MAX(SensorTime) = SensorTime
This means the maxmum value is equal to the value of this row.
The document of MAX( ) function is here:
http://technet.microsoft.com/en-us/library/ms187751.aspx
So, Your code could go something like this:
IF NOT EXISTS (
SELECT * FROM Sensor1 WHERE SensorTime <= #date
AND SensorTime = MAX(SensorTime) AND SensorValue = #value
)
INSERT INTO Sensor1 (SensorTime, SensorValue) VALUES (#date, #value)
Hope this helps.
I am trying to fetch data on the basis of first name and last name. I have two DB replica of one another except for few extra data in one DB. Below is the stored procedure for the same. The problem is that I want data fetched first part of the(ie is if I search for ar it should show names starting with ar like arron but not in the middle like Sharon). The query is working fine with one db & not with the other one.
ALTER PROCEDURE [dbo].[SEARCH]
(
#firstName nvarchar(50),
#lastName nvarchar(50),
#state nvarchar(50),
#county nvarchar(50),
#searchspan nvarchar(5)
)
AS
BEGIN
declare #queryString nvarchar(max)
declare #countyId nvarchar(50)
SET QUOTED_IDENTIFIER OFF
Create table #temp1(
county nvarchar(50) NULL,
ID nvarchar(50) NULL,
name nvarchar(200) NULL,
state nvarchar(50) NULL,
FirstName nvarchar(50) NULL,
LastName nvarchar(50) NULL,
county nvarchar(50) NULL,
)
set #queryString = 'insert into #temp1 select distinct a.Source as county, a.ID as ID, a.FirstName +'' ''+ a.LastName as name, ''' +
#state +''' as state,a.FirstName,a.LastName,b.county, from Person a, CountySite b where 1=1 and a.Source=b.sourcecounty '
if(#searchspan<>'')
BEGIN
set #queryString = #queryString = 1'
END
EXECUTE sp_executesql #queryString
set #queryString ='select county, ID, name, state,col_FirstName,col_LastName,col_county, from #temp1 where 1=1 '
if(#firstName <> '')
BEGIN
set #queryString = #queryString+ ' and UPPER(col_FirstName) like ''' +#firstName +'%'''
END
if(#lastName <> '')
BEGIN
set #queryString = #queryString + ' and UPPER(col_LastName) like ''' +#lastName +'%'''
drop table #temp1
END
TSQL is not case-sensitive and you don't need to use UPPER
Also change your query to
set #queryString = #queryString + ' and col_LastName like #lastName +'%'
Try this
SET #queryString = #queryString + ' AND col_LastName LIKE '''+#lastName +'%'''
Do you have profiler so that you can see the query that is being executed on the second DB? Just to ensure that it's the same. Just for grins you may want to try dropping and re-executing the SP on the DB's.