What's wrong with my stored procedure shown here? [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm trying to write a practice stored procedure query.
DELIMITER $$
CREATE PROCEDURE Select_All_Products_Ordered()
BEGIN $$
SELECT *
FROM northwind.Customers
ORDER BY CompanyName;
END $$
DELIMITER ;
It does not recognize the characters' first delimiter, the parentheses after Ordered(), the table name, nor the CompanyName.

Stored Procedure Declaration Syntax
T-SQL (the version of SQL used by SQL Server) does not declare stored procedure parameters with parenthesis. Instead it puts the parameter list between the procedure name and the keyword AS like this:
CREATE PROCEDURE Select_All_Products_Ordered
#myparameter int = 5
AS
-- ...
The procedure does not have to have any parameters, in which case the AS simply follows the procedure name. As such the parenthesis in your code should be replaced with the keyword AS.
DELIMITER
DELIMITER is not used in T-SQL.
This keyword is used in MySql (and possibly other databases) because they are unable to tell if the ; characters in the stored procedure body delimit the end of the the procedure or the end of one statements within the procedure. So to get around this the delimiter is redefined.
T-SQL in contrast will interpret everything from the AS keyword to the end of the batch as part of the stored procedure. As such it does not get confused by the ; characters and does not need to have the delimiter redefined.
The batch will normally run to the end of the file, however, most T-SQL editors will split a script up into batches to send to the server. This is normally done by splitting the script on the word GO at the start of a line. Note it is the editor that does this not SQL Server. Editors like SQL Server Management Studio (SSMS) can have this configured in the settings to a different pattern if you don't like GO. Also libraries like ADO.Net do not do this, so you have to split the script up yourself and send each batch via a separate server call.
BEGIN and END
BEGIN and END are only required if you wish to group a set of statements in to a block. This is useful for WHILE statements for example. As T-SQL treats everything from the AS keyword to the end of the batch as part of the stored procedure, there is no need for them here. That said it won't hurt if you want to leave them.
Missing Schema
Objects such as tables are grouped within SQL Server databases into Schemas. These each have a name, but the default one is dbo. You have used a multipart reference to the Customer table, however though you have given the database and table name you have not given the schema name. To specify the schema you put it between the database and server name like this northwind.dbo.Customers.
It is possible to leave out the schema name and SQL Server will use the default for the database, but in this case you need two dots like this northwind..Customers.
It is also possible to reference a table on a different server if a connection to the other server is registered with the one you are running on. In this case you would use a four part identifier ServerName.DatabaseName.SchemaName.TableName.
You can omit items from the start for the things the server is expected to know. So if you are connected to a particular database you can ommit the server name and database name. Also as mentioned the schema can be omitted and the default for the logged in user will be assumed.
Conclusion
So in order to get the stored procedure to run on SQL Server using a client tool like SQL Server Management Studio you would write it like this (I've included a call to the procedure at the end to show the batch separator, but this isn't required):
CREATE PROCEDURE Select_All_Products_Ordered
AS
SELECT *
FROM northwind.dbo.Customers
ORDER BY CompanyName;
GO
EXEC Select_All_Products_Ordered
GO
More detailed information about T-SQL's stored procedure syntax can be found on Microsoft's Docs site under CREATE PROCEDURE (Transact-SQL).

Related

Loop Through All SSMS Databases without Recreating Stored Procedure

Background Information:
In Python, I might write something like this if I want to apply the same logic to different values in a list.
database_list = ["db_1", "db_2", "db_3"]
for x in range(0,len(database_list),1):
print("the database name is " + database_list[x])
What I am trying to do:
What I am trying to do in SSMS, is pull a list of DB objects for each database. I created a stored procedure to pull exactly what I want, but I have to run it against each database, so 10 databases mean running it 10 times.
My goal is to do this with a T-SQL query instead of Python.
I tried doing something like this:
exec sp_MSforeachdb 'USE ?; EXEC [dbo].[my_stored_procedure]';
The problem with this is, [dbo].[my_stored_procedure] has to exist in every database I want to do this in.
How can I create the stored procedure in 1 database, but execute it for all databases or a list of databases that I choose?
I know what you are trying to do and if it's what I think (you seem reluctant to actually say!) you can do the following:
In the master database, create your procedure. Normally you wouldn't do this, but in this case you must prefix it sp_
use master
go
create procedure sp_testproc as
select top 10 * from sys.tables
go
Now if you run this, it will return tables from the master database.
If you switch context to another database and exec master.dbo.sp_testproc, it will still return tables from the master database.
In master, run
sys.sp_MS_marksystemobject sp_testproc
Now switch context to a different database and exec master.dbo.sp_testproc
It will return tables from the database you are using.
Try creating your sproc in master and naming it with an sp_ prefix:
USE master
GO
CREATE PROCEDURE sp_sproc_name
AS
BEGIN
...
END
GO
-- You *may* need to mark it as a system object
EXEC sys.sp_MS_marksystemobject sp_sprocname
See: https://nickstips.wordpress.com/2010/10/18/sql-making-a-stored-procedure-available-to-all-databases/
It should then be available in all dbs
Create the stored procedure in the Master database with the sp_ prefix, and use dynamic SQL in the stored procedure so it resolves object names relative to the current database, rather than the database which contains the stored procedure.
EG
use master
go
CREATE OR ALTER PROCEDURE [dbo].[sp_getobjects]
AS
exec ('
select *
from [sys].[objects]
where is_ms_shipped = 0
order by type, name
')
go
use AdventureWorks2017
exec sp_getobjects
#LunchBox - it's your single stored procedure (that you create in one database) that is actually going to need to contain the "exec sp_MSforeach ...." command, and instead of the command to be executed being "EXEC ", it will need to be the actual SQL that you were going to put into the stored proc.
Eg. (inside your single stored procedure)
EXEC sp_MSforeachdb 'USE ?; SELECT * FROM <table>; UPDATE <another table> SET ...';
Think of the stored procedure (that you put into one database) as being no different than your Python code file - if you had actually wanted to achieve the same thing in Python, you would have either needed to create the stored proc in each database, or build the SQL statement string in Python and execute it against each database.
I understand what you thought you might be able to achieve with SQL, but stored procedures really don't work the way you were expecting. Even when you're in the context of a different database, but you run EXEC <different_db>.stored_proc, that stored proc ends up running in the context of the database in which it exists (not your context database).
Now, the only one issue you may come up against is that the standard sp_MSforeachdb stored proc has a limit of 2000 characters for the command that can be executed (although, it does have multiple "command" parameters, this may not be practical if you were planning on running a very large code block, perhaps with variables that carry all the way through). If this is something that might impact what you're intending to do, you could do a search online for "sp_MSforeachdb alternatives" - there seem to be a handful that people have created where the command parameter can contain a larger string.

The real function of the "GO" Statement in SQL?

I heard that GO statement separates the command batches in SQL. And the CREATE transaction should be the only query on a batch.
But when i try:
Create database dbTest
Create table tbSomething(ID int primary key,Name varchar(30))
GO
The output is still SUCCESS.
So how does the GO Statement affect the SQL batches?
GO is used to divide a script into multiple batches.
The word GO is not a sql statement. It is understood by the SQL batch processor (for example SSMS) not by SQL Server.
Simply put, if GO appears on a line on its own, SSMS sends each section delimited by GO as a separate batch. SQL Server never sees the GO lines, only the SQL between them.
Because SQL Server has a syntactic rule that stored procedures must be defined in a batch on their own, you will often find database creation scripts which use GO to delimit the batches so that multiple stored procedures can be created from one script. However it is the client software which understands GO and divides the batches, not SQL server.
'GO' statement in SQL server is to just sends a signal to take the current batch of SQL statements for execution.
To tell in simple words, it works like a delimiter.
It is an indication of end of SQL statement [i.e., 1 batch that needs to be executed].

Getting results from Oracle stored procedure insertion through pyodbc

I am using pyodbc (version 3.0.7) to access an Oracle (version 11g) database. We are writing stored procedures to handle the insertions. The primary keys for inserted objects are assigned with triggers, so we want to get the newly-inserted object's primary key into python after the stored procedure is called by the python script. (Due to client requirements, we don't have the flexibility of changing database, libraries, etc.)
According to the pyodbc documentation, return (OUT) parameters in stored procedures are not supported. Neither are stored functions. The documentation suggests to add a SELECT statement to the end of a stored procedure to get results out. However, we are new to SQL scripting, and Google searching for the last two days has turned up a lot of information for SQLServer and other databases, but next to nothing for Oracle. Trying the SQLServer examples on the Oracle db has not been tremendously helpful, as the Oracle SQL Developer shows various errors with the syntax (DECLARE where one shouldn't be, INTO required for SELECT statements, etc.).
Ultimately, we want the stored procedure to insert a new object, and then we want to somehow get the newly-created primary key for that object.
Here is an example of a stored procedure that correctly inserts an object (note that if obj_id is given as "None" in python, then the object is assigned a new primary key by a trigger):
CREATE OR REPLACE PROCEDURE insert_an_obj (an_obj_id NUMBER) AS
new_primary_key NUMBER;
BEGIN
INSERT INTO OBJS (OBJ_ID) VALUES (an_obj_id) RETURNING OBJ_ID INTO new_primary_key;
-- A SELECT statement should go here in order to get the new value for new_primary_key.
END insert_an_obj;
Supposedly, a SELECT statement at the end of the stored procedure will make it so the next time my script calls cursor.fetchall(), the script would get a list of whatever was selected. However, I have been unable to get this to work. Some failed SELECT examples (one of which might go in the stored procedure above in place of the SELECT comment) include the following:
-- These fail to compile because SQL Developer doesn't like them (though various sources online said that they work on SQLServer):
SELECT * FROM OBJS WHERE OBJ_ID=new_primary_key;
SELECT OBJ_ID FROM OBJS WHERE OBJ_ID=new_primary_key;
Like I said, I'm new to SQL, and likely I just need to know the proper syntax to get the SELECT statement working nicely in Oracle. Any suggestions? Or is there something that I'm misunderstanding?
As mentioned by Justin Cave in the comment above, "you can't just put a SELECT in a stored procedure to return data to the client." At least not with Oracle 11g. He continues: "In 11g, the only way to regurn data from a stored procedure is to have an OUT parameter", which AFIK, not possible using version 3.0.7 of pyodbc.

Case sensitive variable names in SQL Server? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
When I execute this format of SQL command: SP_HELPTEXT Sproc1 .
The result set will display Could not find stored procedure 'SP_HELPTEXT'. But if i will replace the SQL command to lower case like sp_helptext Sproc1 , it definitely displays the content of Sproc1.
Im using the Sproc1 in my program and when the program executes Sproc1 it will return a message:
Must declare the variable '#Variable1'.
Although I've already declared that specific variable.
I have a hint that the issue is related to collation, case-sensitive or insensitive settings. Does anybody know how to resolve ?
Another situation where case sensitive variable names appear:
CREATE PROCEDURE Foo #customerID int AS
PRINT #customerId
You have a case sensitive server collation.
Your database has a (as you have shown) a case insensitive collation but when you have a case issue with variables it is the server collation that matters.
The same goes for sp_helptext which is a stored procedure defined in database master with lowercase. So when you call SP_HELPTEXT it is not found.
To fix your stored procedure to work in a case sensitive server collation you have to make sure that every reference to the variable #Variable1 is exactly that. Not #variable1 or #VARIABLE1.
Use this to check what server collation you have.
SELECT SERVERPROPERTY('collation');
From the SQL Server Books Online:
COLLATE (Transact-SQL)
The collation of an identifier depends on the level at which it is defined.
Identifiers of instance-level objects, such as logins and database names, are assigned the default collation of the instance.
Identifiers of objects within a database, such as tables, views, and column names, are assigned the default collation of the database.
For example, two tables with names different only in case may be created in a database with case-sensitive collation, but may not be created in a database with case-insensitive collation. For more information, see Database Identifiers.
The identifiers for variables, GOTO labels, temporary stored procedures, and temporary tables are in the default collation of the server instance.
Variables, GOTO labels, temporary stored procedures, and temporary tables can be created when the connection context is associated with one database, and then referenced when the context has been switched to another database.
See also
MSDN forums: Why are my SP's throwing a case error when pushing to a db using BIN collation?
Case sensitive variables in SQL Server
SQL Server stored procedure case sensitive?

Alias Columns Returned by a Stored Procedure [SQL Server 2008]

I'm not super familiar with stored procedures in general and SQL Server/T-SQL specifically. I'm wondering if there is a way to alias or rename the columns returned by a stored procedure without modifying the stored procedure itself.
Here is the stored procedure call I have now.
EXEC sp_GetNearbyLocations 38.858907, -77.261358
It returns records with the following columns:
State
Zip
Phone
StartDate
Directions
Hours
Latitude
Longitude
Distance
However I'd like them to be all lowercase and not camel cased. Sadly, I do not control the stored procedure so I cannot change it, just my call to it. Is this possible in SQL Server 2008?
If SQL Server 2012 you can use the WITH RESULT SETS feature.
Otherwise this isn't possible it would require you to insert the results into some kind of intermediate temporary table then select from that.
(You could do this without creating the temp table explicitly by using OPEN ROWSET however)
You could write your own proc that simply calls the other one, aliases the columns and returns that.
On a side note - why does the case of the column names matter to you?