Create SQL Server tables and stored procedures in one script? - sql

I have a SQL script that is setting up two database tables with their keys and constraints without any problem. I won't include the whole code but the 'skeleton' of it looks like this:
BEGIN
CREATE TABLE [table] (
)
CREATE TABLE [table2] (
)
ALTER TABLE table...
ALTER TABLE table2....
END
I am stuck trying to add stored procedures to this script though, ideally I would like to include this all within the same script. Could someone tell me how to include the following stored procedure into the above script?
CREATE PROCEDURE Test
#x int
AS
BEGIN
SELECT COUNT(*)
FROM table
END
GO
I have tried putting it towards the end of the script and have also tried with and without the BEGIN, END and GO tags but I keep getting an error that says 'incorrect syntax near PROCEDURE'.

Try it like this:
USE BDNAME
GO
BEGIN
CREATE TABLE [table] (
)
CREATE TABLE [table2] (
)
ALTER TABLE table...
ALTER TABLE table2....
END
USE BDNAME
GO
CREATE PROCEDURE Test
#x int
AS
BEGIN
SELECT COUNT(*)
FROM table
END
GO

Instead of using BEGIN END, put GO between all your Statements like Create, Alter. Also I would like to inform you that putting GO will create blocks in your script, so if you create some local variable in one block, it is not accessible in another.
CREATE Table Table1(
--Your Code
)
GO
CREATE PROCEDURE Test
#x int
AS
BEGIN
SELECT COUNT(*)
FROM Table1
END
GO
--Continue your script
Hope this helps.

Related

Use (insert and select) temp table in the store procedure

I use below code to create procedure to using temp table
Go
create procedure testTempTable
as
INSERT INTO #resultTbl (code,userName) SELECT code,userName FROM Customer
select * from #resultTbl
Go
When I want to run the procedure with exec testTempTable says
Invalid object name '#resultTbl'.
How can I use temp table in the procedure?
Because your temp table might not be created, so you can't get result set from #resultTbl. you can try to use SELECT ... INTO temp table or create a temp table before you use it.
create procedure testTempTable
as
BEGIN
SELECT code,userName
INTO #resultTbl
FROM Customer
SELECT *
FROM #resultTbl
END
Go

How to execute commands/functions in order

I'm writing a long SQL query that I will be using to automate the process of ingesting large-ish flat files (using python to flatten heavily nested JSON files) and normalizing them for scalability and ease of use with PowerBI reports and dashboards.
Currently, I've got a long process that slices the table into multiple tables, generates mapping tables between them and the primary table, remaps a PK/FK link back to the primary table and drops the old unneeded columns from the primary table.
I'm still building and debugging the script, and I'm getting really frustrated with something that I think I'm doing wrong as I'm not very proficient in SQL.
Currently, if I try to run all of my code at once it will fail saying I'm using invalid column names. The column names are invalid with the tables in their current state, but if it would simply execute from top to bottom, they would be valid by the time it got to them. I've got to highlight and execute my drop tables statement by itself every time I want to rerun the entire script even though I've got the same drop tables statement at the top.
Any advice on how to make the script simply execute from top to bottom or how to make it step through and ignore the "current" state of the tables (prior to execution) would be greatly helpful.
Some example pseudo of what I've got:
CREATE OR ALTER PROCEDURE DropTables
AS
BEGIN
DROP TABLE IF EXISTS
t1,
t2,
t3
END
GO
CREATE OR ALTER PROCEDURE GenerateTable1
AS
BEGIN
~make table~
END
GO
CREATE OR ALTER PROCEDURE GenerateTable2
BEGIN
~make table~
END
GO
CREATE OR ALTER PROCEDURE GenerateTable3
BEGIN
~make table~
ALTER TABLE t1 ADD ~fk from t3~
UPDATE t1
SET ~keys to match~
FROM t3 WHERE t1.old_col = t3.new_col
ALTER TABLE t1
DROP COLUMN old_col
END
GO
EXEC DropTables
GO
EXEC GenerateTable1
GO
EXEC GenerateTable2
GO
EXEC GenerateTable3
Upon executing this I get "Invalid column name old_col" because old_col currently doesnt exist, however, if it would just execute from top to bottom, old_col would exist when it got to it.
Current workaround is highlighting droptables and executing it by itself first, then I can execute everything at once
GO breaks the script into batches. You just need to scope the batches so each one compiles. Or use dynamic SQL which is just a different way to issue separate batches.
It may not be the most elegant solution, but simply wrapping everything in an exec block with single quotes seems to work. "EXEC(' stuff ');" SQL doesnt try to get ahead of itself and is forced to execute in order from top to bottom, example:
CREATE OR ALTER PROCEDURE DropTables
AS
BEGIN
EXEC('
DROP TABLE IF EXISTS
t1,
t2,
t3
')
;
END
GO
CREATE OR ALTER PROCEDURE GenerateTable1
AS
BEGIN
EXEC('
~make table~
')
;
END
GO
CREATE OR ALTER PROCEDURE GenerateTable2
BEGIN
EXEC('
~make table~
')
;
END
GO
CREATE OR ALTER PROCEDURE GenerateTable3
BEGIN
EXEC('
~make table~
ALTER TABLE t1 ADD ~fk from t3~
UPDATE t1
SET ~keys to match~
FROM t3 WHERE t1.old_col = t3.new_col
ALTER TABLE t1
DROP COLUMN old_col
')
;
END
GO
EXEC DropTables
GO
EXEC GenerateTable1
GO
EXEC GenerateTable2
GO
EXEC GenerateTable3

Nested Stored Procedure

How can i insert values of a nested stored procedure into a table.
For example if i created a stored procedure like this.
Create procedure New
begin
create table #tmp
(
id int,
name varchar(50)
);
insert into #tmp
exec stored_procedure 1,2;
insert into #tmp
exec stored_procedure 1,2;
select * from #tmp
end
Now if I execute this command, SQL Server will display error:
insert into #table
exec New;
Does anyone have a solution for this problem? Please share
Right now you’re not returning any data from your procedure New. If you want it to return data for your calling code to insert you’ll need a select statement in it.
Eg add a line at the end:
SELECT * FROM #tmp;
Also, you can’t nest INSERT EXEC statements. See this answer for more details
You can't do a insert with de values returned by a Stored Procedure.
In your case the easiest way is to change de stored procedures by table functions.
You can find more about table functions here
My opinion is to make it simple if u can.

Calling a stored procedure in the SELECT command

I have a stored procedure ModifiedName, is it possible to list the name of all the rows in a table and display the "modified name" next to them?
Something along:
SELECT name, EXEC ModifiedName name
FROM table
but which would work...
First you have to write a function instead of procedure. You cannot call a procedure inside a select statement ,But a function can.
Inside the function write your logic to modify the name and use it in the select query.
For example write a function like below.(This will append 'Mr.' with name )
CREATE FUNCTION dbo.ModifiedName ( #name VARCHAR(50))
RETURNS VARCHAR(150)
AS
BEGIN
DECLARE #ModifiedName VARCHAR(150)
SET #ModifiedName= 'Mr.'+#name
RETURN #ModifiedName
END
And use the below script to get the original name and modified name in the select list.
SELECT name, dbo.ModifiedName (name)
FROM table
You can do
CREATE TABLE SomeName(... appropriate definitions ...);
INSERT INTO SomeName
EXEC YourSP;
SELECT * FROM SomeName;
But - to be honest - I think you are trying something you should solve in another way...
Create a function
Try to inline your logic
UPDATE This is for #NEER
Hi NEER, don't know what you mean with your comment, but try this:
CREATE PROCEDURE dbo.tmpTest AS
BEGIN
SELECT TOP 3 COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
END
GO
CREATE TABLE #tmpTable(ColName NVARCHAR(MAX));
INSERT INTO #tmpTable
EXEC dbo.tmpTest;
SELECT * FROM #tmpTable;
GO
DECLARE #tmpTbl TABLE(ColName NVARCHAR(MAX));
INSERT INTO #tmpTbl
EXEC dbo.tmpTest;
SELECT * FROM #tmpTbl;
GO
DROP TABLE #tmpTable;
DROP PROCEDURE dbo.tmpTest;
But - in general - if you just want to read data one should rather use a VIEW or an inline TVF. Procedures are designed to do something...
If parameterless sp, you can with a temp table. Otherwise you should use a function.
CREATE TABLE #tmp (Name INT)
INSERT INTO #tmp
EXEC ModifiedName
SELECT name, (SELECT TOP 1 Name FROM #tmp) name
FROM table

Select Values From SP And Temporary Tables

I have a Stored Procedure in MSSQL 2008, inside of this i've created a Temporary Table, and then i executed several inserts into the temporary Table.
How can i select all the columns of the Temporary Table outside the stored procedure? I Mean, i have this:
CREATE PROCEDURE [dbo].[LIST_CLIENTS]
CREATE TABLE #CLIENT(
--Varchar And Numeric Values goes here
)
/*Several Select's and Insert's against the Temporary Table*/
SELECT * FROM #CLIENT
END
In another Query i'm doing this:
sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO
SELECT *
INTO #CLIENT
FROM OPENROWSET
('SQLOLEDB','Server=(local);Uid=Cnx;pwd=Cnx;database=r8;Trusted_Connection=yes;
Integrated Security=SSPI',
'EXEC dbo.LIST_CLIENTS ''20110602'', NULL, NULL, NULL, NULL, NULL')
But i get this error:
Msg 208, Level 16, State 1, Procedure LIST_CLIENTS, Line 43
Invalid object name '#CLIENT'.
I've tried with Global Temporary Tables and It doesn't work.
I know that is the scope of the temporary table, but, how can i get the table outside the scope of the SP?
Thanks in advance
I think there is something deeper going on here.
One idea is to use a table variable inside the stored procedure instead of a #temp table (I have to assume you're using SQL Server 2005+ but it's always nice to state this up front). And use OPENQUERY instead of OPENROWSET. This works fine for me:
USE tempdb;
GO
CREATE PROCEDURE dbo.proc_x
AS
BEGIN
SET NOCOUNT ON;
DECLARE #x TABLE(id INT);
INSERT #x VALUES(1),(2);
SELECT * FROM #x;
END
GO
SELECT *
INTO #client
FROM OPENQUERY
(
[loopback linked server name],
'EXEC tempdb.dbo.proc_x'
) AS y;
SELECT * FROM #client;
DROP TABLE #client;
DROP PROCEDURE dbo.proc_x;
Another idea is that perhaps the error is occurring even without using SELECT INTO. Does the stored procedure reference the #CLIENT table in any dynamic SQL, for example? Does it work when you call it on its own or when you just say SELECT * FROM OPENROWSET instead of SELECT INTO? Obviously, if you are working with the #temp table in dynamic SQL you're going to have the same kind of scope issue working with a #table variable in dynamic SQL.
At the very least, name your outer #temp table something other than #CLIENT to avoid confusion - then at least nobody has to guess which #temp table is not being referenced correctly.
Since the global temp table failed, use a real table, run this when you start your create script and drop the temp table once you are done to make sure.
IF OBJECT_ID('dbo.temptable', 'U') IS NOT NULL
BEGIN
DROP TABLE dbo.temptable
END
CREATE TABLE dbo.temptable
( ... )
You need to run the two queries within the same connection and use a global temp table.
In SQL Server 2008 you can declare User-Defined Table Types which represent the definition of a table structure. Once created you can create table parameters within your procs and pass them a long and be able to access the table in other procs.
I guess the reason for such behavior is that when you call OPENROWSET from another server it firstly and separately requests the information about procedure output structure (METADATA). And the most interesting thing is that this output structure is taken from the first SELECT statement found in the procedure. Moreover, if the SELECT statement follows the IF-condition the METADATA request ignores this IF-condition, because there is no need to run the whole procedure - the first met SELECT statement is enough. (By the way, to switch off that behavior, you can include SET FMTONLY OFF in the beginning of your procedure, but this might increase the procedure execution time).
The conclusions:
— when the METADATA is being requested from a temp table (created in a procedure) it does not actually exists, because the METADATA request does not actually run the procedure and create the temp table.
— if a temp table can be replaced with a table variable it solves the problem
— if it is vital for the business to use temp table, the METADATA request can be fed with fake first SELECT statement, like:
declare #t table(ID int, Name varchar(15));
if (0 = 1) select ID, Name from #t; -- fake SELECT statement
create table #T (ID int, Name varchar(15));
select ID, Name from #T; -- real SELECT statement
— and one more thing is to use a common trick with FMTONLY (that is not my idea) :
declare #fmtonlyOn bit = 0;
if 1 = 0 set #fmtonlyOn = 1;
set fmtonly off;
create table #T (ID int, Name varchar(15));
if #fmtonlyOn = 1 set fmtonly on;
select ID, Name from #T;
The reason you're getting the error is because the temp table #Client was not declared before you ran the procedure to insert into it. If you declare the table, then execute the list proc and use direct insert -
INSERT INTO #Client
EXEC LIST_CLIENTS