Programmatic T-SQL in ad-hoc sql scripts - sql

Is it possible to use T-SQL programming constructs outside the confines of stored procedures and functions? Specifically, can they be used in ad-hoc sql scripts? If so, is the full range of capabilities available (aside from passing in parameters and returning values that I guess would only be supported in stored procedures and functions)?
I'm from an Oracle PL/SQL background. PL/SQL can be used in stored procedures and functions, but also within anonymous PL/SQL code blocks that can be used in ad-hoc sql scripts and do not get stored in the DB. I'd like to know if T-SQL has similar capabilities.

Yes they can take this example solution to the fizzbuzz problem:
declare #counter int
declare #output varchar(15)
set #counter = 1
while #counter < 101
begin
set #output = ''
if #counter % 3 = 0
set #output = 'Fizz'
if #counter % 5 = 0
set #output = #output + 'Buzz'
if #output =''
set #output = #counter
print #output
set #counter = #counter + 1
end
Of course don't fall into the trap of using procedural code to work with data, SQL works best treating data as a set.

Related

How to represent dynamic query in SQL Server view

I have the following SQL code:
DECLARE #i INT = 1;
DECLARE #sql_code varchar(max) = '';
DECLARE #repeats INT = 4;
WHILE #i <= #repeats
BEGIN
SET #sql_code = #sql_code+'SELECT ''foo'+cast(#i as varchar)+''' as bar UNION ALL '
SET #i = #i + 1
END;
SET #sql_code = LEFT(#sql_code,LEN(#sql_code) - 10)
exec (#sql_code)
,which when run in SSMS produces this:
bar
----
foo1
foo2
foo3
foo4
How can I reproduce the same result as view (dynamically)?
I know you can't use declarations in view, but could it be done through stored procedure or function?
You can't use dynamic sql inside a view. But yes you can create table valued User-Defined functions as mentioned in this post.
Link to the post: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/3cdeda6c-af19-46e9-b89f-e575fecd475b/dynamic-query-in-view?forum=transactsql
Answer by Gavin Campbell should give you the idea of what can be done.
Note : For more information on Table valued User-Defined Functions: Visit this documentation:
https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms191165(v=sql.105)?redirectedfrom=MSDN
Actually, despite what Utsav's good answer says, you can do anything if you put your mind to it. 😉
While this is generally not recommended (this answer is for informational purposes), there are certain use cases where it makes sense to use OPENQUERY() inside a View. OPENQUERY() allows you to execute raw SQL against a remote or local SQL Server. Either in the raw SQL itself, or probably more organized in a stored procedure, there's essentially no limitations on the queries you can run, including dynamic SQL.
Example:
CREATE PROCEDURE dbo.RunSomeDynamicSQL
AS
DECLARE #DynamicSQL NVARCHAR(MAX) =
'
SELECT 1 AS Foobar;
';
EXEC sp_executesql #DynamicSQL;
GO
CREATE VIEW dbo.SomeViewThatExecutesDynamicSQL
AS
SELECT Foobar
FROM OPENQUERY
(
LocalServerName,
'
EXEC YourDatabaseName.dbo.RunSomeDynamicSQL
WITH RESULT SETS
((
Foobar INT
));
'
);
GO
SELECT Foobar
FROM dbo.SomeViewThatExecutesDynamicSQL;
You'll notice I'm using the WITH RESULT SETS keyword when executing my procedure inside of OPENQUERY(). This is because OPENQUERY() needs to know the shape of the result set from the executing query. This is one way to describe that when executing a procedure.
One use case for using OPENQUERY() in a View is so you can maximize your ability to performance tune your query (e.g. inside a stored procedure) without losing consumability of the database object.
One important fact about using OPENQUERY() is that the SQL Server Engine always estimates the cardinality of the results to be 10,000 rows. This means if your result set is much larger than 10,000 rows, for example 10 million rows, then you may not get the most optimal execution plan to serve your query.
Also, despite my informational answer, you can of course use a stored procedure alone if that's sufficient for your use case.
could it be done through stored procedure
Sure, just wrap a stored procedure around your code:
CREATE PROCEDURE dbo.SomeStoredProcedure
AS
DECLARE #i INT = 1;
DECLARE #sql_code NVARCHAR(MAX) = '';
DECLARE #repeats INT = 4;
WHILE #i <= #repeats
BEGIN
SET #sql_code = #sql_code+'SELECT ''foo'+cast(#i as varchar)+''' as bar UNION ALL '
SET #i = #i + 1
END;
SET #sql_code = LEFT(#sql_code,LEN(#sql_code) - 10)
EXEC sp_executesql #sql_code
Note I changed the last line of your code to use sp_executesql because it minimizes your risk for SQL injection issues. You should always use that procedure for dynamic SQL execution instead of directly executing your SQL string.

How many characters can we get in a SELECT or a PRINT statement? [duplicate]

This question already has answers here:
How do I view the full content of a text or varchar(MAX) column in SQL Server 2008 Management Studio?
(11 answers)
Closed 3 years ago.
I have a varchar(max) variable named as QUERY. I'm storing a bulk of create queries in it. Its length is almost 65000+ characters. But whenever I print it or select it, it does not returns me the whole result.
DECLARE #QUERY AS VARCHAR(MAX)
SET #QUERY='';
//repopulating #QUERY with queries until the lengths reaches more than 65000
//characters, then
SELECT LEN(REPLACE(#QUERY, 'N', ''))--to check the length
PRINT #QUERY as QUERY --to get the result in print
SELECT #QUERY as QUERY --to get the result in select
How can I get my whole result? All this work is being done in a stored procedure. And the result of the procedure should be the bunch of queries from the select statement.
Try
PRINT CAST(#QUERY AS NTEXT)
ntext , text, and image data types has been removed in a latest version of Microsoft SQL Server. Avoid using these data types in new development work, and plan to modify applications that currently use them.
You could do a WHILE loop based on the count on your script length divided by 8000.
EG:
DECLARE #Counter INT
SET #Counter = 0
DECLARE #TotalPrints INT
SET #TotalPrints = (LEN(#QUERY) / 8000) + 1
WHILE #Counter < #TotalPrints
BEGIN
-- Do your printing...
SET #Counter = #Counter + 1
END
FIDDLE DEMO

Dynamic change schema in SQL procedure

I have a database with multiple schemas. In every schema I got table called [Logs], so my database tables looks like:
[s1].[Logs]
[s2].[Logs]
[s3].[Logs]
...
[sN].[Logs]
Every day I would like to run stored procedure, which will do same operations on every above table. Is there a way to pass schema name into stored procedure? I am using SQL on Azure.
No, it is not - unless the SP Uses then dynamic SQL to execute some SQL String you constructed in the SP.
This happens via the sp_executesql stored procedure
http://technet.microsoft.com/en-us/library/ms188001.aspx
has more information.
Microsoft has a few undocumented procedures that perform "foreach" operations on tables (sp_msforeachtable) and databases (sp_msforeachdb). Both of these rely on another undocumented proc called sp_msforeachworker which you might be able to exploit to create a foreachschema type of routine. Theres an article (reg required) here that demonstrates this approach.
That said, its unlikely Azure supports anything of these, so you might have to fashion your own using a crude loop:
declare #schemas table (i int identity(1,1), name sysname);
insert into #schemas
select name from sys.schemas where name like 's[0-9]%';
declare #i int, #name sysname, #cmd nvarchar(max);
select #i = min(i) from #schemas;
while #i is not null
begin
select #name = name from #schemas where i = #i;
set #cmd = replace(N'select count(*) from [{0}].[Logs];', '{0}', #name);
print #cmd;
--exec(#cmd);
select #i = min(i) from #schemas where i > #i;
end

How to perform a task repeatedly in SQL?

There is a SQL script with some declared variables. I want to run this script for various sets of values of these variables and see the outputs. How do I do this?
Just a note: this answer is copied from here but is a great resource for what you are asking.
More examples for set-based vs. procedural can be found here, here and here.
And here is an actual example in SQL code:
DECLARE #someFlag INT
SET #someFlag = 0
WHILE (#someFlag <=5)
BEGIN
PRINT #someFlag
SET #someFlag = #someFlag + 1
END
GO
If you have the appropriate permissions to do it, you could set up the script as a stored procedure and then run the procedure multiple times. Reference on how to do it: http://msdn.microsoft.com/en-us/library/ms187926(v=sql.100).aspx
You don't have to make a permanent proc either, if you don't need it or want it in whatever database you're running it in, you can set it up as a temp proc instead.
So instead of CREATE PROCEDURE dbo.usp_SomeProcedure AS ....
you would do CREATE PROCEDURE #usp_SomeProcedure
Your other option is to put your script into an nvarchar(max) variable and use that along with your other variables to run sp_executesql (http://msdn.microsoft.com/en-us/library/ms188001.aspx).
I would either use a Cursor or a While loop (preference would be the While). It would be something like this
DECLARE #i INT
SET #i = 1
WHILE (#i <=10)
BEGIN
-- do whatever you need to do
SET #i = #i + 1
END

MS SQL - High performance data inserting with stored procedures

Im searching for a very high performant possibility to insert data into a MS SQL database.
The data is a (relatively big) construct of objects with relations. For security reasons i want to use stored procedures instead of direct table access.
Lets say i have a structure like this:
Document
MetaData
User
Device
Content
ContentItem[0]
SubItem[0]
SubItem[1]
SubItem[2]
ContentItem[1]
...
ContentItem[2]
...
Right now I think of creating one big query, doing somehting like this (Just pseudo-code):
EXEC #DeviceID = CreateDevice ...;
EXEC #UserID = CreateUser ...;
EXEC #DocID = CreateDocument #DeviceID, #UserID, ...;
EXEC #ItemID = CreateItem #DocID, ...
EXEC CreateSubItem #ItemID, ...
EXEC CreateSubItem #ItemID, ...
EXEC CreateSubItem #ItemID, ...
...
But is this the best solution for performance? If not, what would be better?
Split it into more querys? Give all Data to one big stored procedure to reduce size of query? Any other performance clue?
I also thought of giving multiple items to one stored procedure, but i dont think its possible to give a non static amount of items to a stored procedure.
Since 'INSERT INTO A VALUES (B,C),(C,D),(E,F) is more performant than 3 single inserts i thought i could get some performance here.
Thanks for any hints,
Marks
One stored procedure so far as possible:
INSERT INTO MyTable(field1,field2)
SELECT "firstValue", "secondValue"
UNION ALL
SELECT "anotherFirstValue", "anotherSecondValue"
UNION ALL
If you aren't sure about how many items you're inserting you can construct the SQL query witin the sproc and then execute it. Here's a procedure I wrote to take a CSV list of groups and add their relationship to a user entity:
ALTER PROCEDURE [dbo].[UpdateUserADGroups]
#username varchar(100),
#groups varchar(5000)
AS
BEGIN
DECLARE #pos int,
#previous_pos int,
#value varchar(50),
#sql varchar(8000)
SET #pos = 1
SET #previous_pos = 0
SET #sql = 'INSERT INTO UserADGroups(UserID, RoleName)'
DECLARE #userID int
SET #userID = (SELECT TOP 1 UserID FROM Users WHERE Username = #username)
WHILE #pos > 0
BEGIN
SET #pos = CHARINDEX(',',#groups,#previous_pos+1)
IF #pos > 0
BEGIN
SET #value = SUBSTRING(#groups,#previous_pos+1,#pos-#previous_pos-1)
SET #sql = #sql + 'SELECT ' + cast(#userID as char(5)) + ',''' + #value + ''' UNION ALL '
SET #previous_pos = #pos
END
END
IF #previous_pos < LEN(#groups)
BEGIN
SET #value = SUBSTRING(#groups,#previous_pos+1,LEN(#groups))
SET #sql = #sql + 'SELECT ' + cast(#userID as char(5)) + ',''' + #value + ''''
END
print #sql
exec (#sql)
END
This is far faster than individual INSERTS.
Also, make sure you just a single clustered index on the primary key, more indexes will slow the INSERT down as they will need to update.
However, the more complex your dataset is, the less likely it is that you'll be able to do the above so you will simply have to make logical compromises. I actually end up calling the above routine around 8000 times.