SQL getting the output from a stored procedure? - sql

Just starting out with SQL, so there's probably a really easy answer here, but I couldn't figure out exactly what i needed to do from a google search.
There's a stored procedure in the database I'm using called dt_char_sp - simply put, the parameters are the date and time as ints, and the stored procedure formats them nicely. I would expect that it works something like this:
EXEC dt_char_sp 20130416, 024356
go
output:
04/06/2013 02:43:56
except the output doesn't happen! I see that there is a variable declared as "#datetime datetime=NULL OUTPUT" and eventually the #datetime variable is filled with the formatted string, but I'm wondering if there's a way to get this output variable?

We cannot be sure without actually seeing the stored procedure, but it sounds like it is using an output parameter.
DECLARE #retval As DATETIME
EXEC dt_char_sp 20130416, 024356, #datetime=#retval OUTPUT
PRINT #retval
go
There is an equivalent way to do this from client code as well.

You need to use a Select statement.
At the end of your query just Select the desired output variable like so :
SELECT #datetime
Another way would be to use an Output Parameter. Declared like so :
#datetime DateTime OUTPUT;

Are you sure that you are doing something to get a return value?
If not, you can select the variable
select #datetime

Please do not burden the SQL Server with lame stuff like formatting strings. It's much too important for that kind of thing. I see this a lot lately, and it's a bad habit.
Please, use your client formatting tools for this...
Something like (for UNIX-type dates)
DateTime dt = new DateTime("1/1/1970").AddDays(myIntDate);
Console.Writeln(dt.ToString("mm/dd/yyyy"));
This is better for a lot of reasons - performance is the big one. You have all the data you need already, there is no reason to make a round-trip to a very expensive server when you don't really need anything from it. All computers can format dates, don't use the server for it.
This IS the correct answer by the way. I don't think Stack Overflow should become the place where if someone asks how to jump off a bridge, we just tell them. When someone is asking how to accomplish something USING THE WRONG METHOD, WE SHOULD TELL THEM THE CORRECT METHOD.

Related

How to recover my data in sql?

By mistake I have not prefixed a Unicode string with N and I have inserted data that now contains ? instead of the original Unicode characters. Using this as an example:
SELECT T.A FROM ( SELECT '男孩 SQL' A) T
It is returning ?? SQL instead of 男孩 SQL.
So how can I get the actual value; what can I use in outer SELECT statement?
If you are declaring a hard coded NVARCHAR string value it is important to use this format:
DECLARE #Variable NVARCHAR(10) = N'YourVariableHere'
Instead of :
DECLARE #Variable NVARCHAR(10) = 'YourVariableHere'
The second method will cause an implicit column conversion which is at best bad for performance and at worst will incorrectly interperit the results. I just found a cool little test for this. Run this script in SQL Server.
SELECT N'௰', '௰';
You will get this as a result.
If you're interested in more information on Implicit Column Conversion look here.
However since you've already inserted this data into your database you are out of luck. There is no way to recover this unless you have the scripts saved somewhere else.
If you have the permissions and powers to insert data into a production system I suggest you exercise more caution next time.

How to change time(7) format from 24 to 12?

I have a variable as time(7), but it gives me values like: '17:25'. I'd like for it to be in this format: '5:25 PM'. Is there a way to do this in SQL 2012 without doing something like this:
DECLARE #aux NVARCHAR(8)='16:45:00'
SELECT CONVERT(VARCHAR(15),CAST(#aux AS TIME),100)
Code gotten from here
No, you cannot do anything about the format SQL Server uses to store the Time datatype. You can only use tricks like the one you mentioned at query-time to deliver the output in a desired format. Or better yet, do the formatting in the front-end application.
you can try to use DATEPART(HH... with case statements or IF/ELSE to alter the times past noon, and CONCAT am or pm on the end

Store result set in memory over multiple queries?

I thought CTEs were perfect for my stored procedure, until I found out they can only be referenced in ONE query (ie the query immediately following the CTE). They now seem fairly pointless.
I'm looking for a way to perform a query, store that result set in memory (not on disk like a temp table or table variable), and then reference it within a stored procedure in multiple SELECT/INSERT/UPDATE statements. Just like a temporary view, or a CTE with a longer scope. But that doesn't seem to exist at all in SQL Server! Does anyone have a solution? Doesn't this seem rather short-sighted on behalf of the CTE functionality?
I agree with the comments. I also don't know precisely how the following would be done, but I think it would work. With that said: have your query generate XML output, store that output in an XML variable, and then use xquery to reference and extract data from it for the rest of the procedure. (But again, I'm not at all sure you can write a "SELECT #XML = ..." query. Maybe OPENXML, or something like that?)

Display DataType and Size of Column from SQL Server Query Results at Runtime

Is there a way to run a query and then have SQL Server management studio or sqlcmd or something simply display the datatype and size of each column as it was received.
Seems like this information must be present for the transmission of the data to occur between the server and the client. It would be very helpful to me if it could be displayed.
A little background:
The reason I ask is because I must interface with countless legacy stored procedures with anywhere from 50 to 5000+ lines of code each. I do not want to have to try and follow the cryptic logic flow in and out of temp tables, into other procedures, into string concatenated eval statement and so on. I wish to maintain no knowledge of the implementation, simply what to expect when they work. Unfortunately following the logic flow seems to be the only way to figure out what exactly is being returned without trying to infer what the actual types of the data string representations om management studio studio or from the native type in .net for example.
To clarify: I am not asking about how to tell the types of a table or something static like that. I'm pretty sure something like sp_help will not help me. I am asking how to tell what the sql server types (ie varchar(25), int...) are of what I have been given. Additionally, changing the implementation of the sprocs is not possible so please consider that in your solutions. I am really hoping there is a command I have missed somewhere. Much appreciation to all.
Update
I guess what I am really asking is how to get the schema of the result set when the result set originates from a query using a temp table. I understand this to be impossible but don't find much sense with that conclusion because the data is being transmitted after all. Here is an example of a stored procedure that would cause a problem.
CREATE PROCEDURE [dbo].[IReturnATempTable]
AS
Create table #TempTable
(
MyMysteryColumn char(50)
)
INSERT #TempTable (
MyMysteryColumn
) VALUES (
'Do you know me?' )
select TOP 50 * FROM #TempTable
What will you do about stored procedures which return different result sets based on their parameters?
In any case, you can configure a SqlDataAdapter.SelectCommand, along with the necessary parameters, then call the FillSchema method. Assuming that the schema can be determined, you'll get a DataTable configured with correct column names and types, and some constraints.
A bit of a long shot, try messing around with SET FMTONLY ON (or off). According to BOL, this "Returns only metadata to the client. Can be used to test the format of the response without actually running the query." I suspect that this will inlcude what you're looking for, as BCP uses this. (I stumbled across this setting when debugging some very oddball BCP problems.)
Could you append another select to your procedure?
If so you might be able to do it by using the sql_variant_property function.
Declare #Param Int
Set #Param = 30
Select sql_variant_property(#Param, 'BaseType')
Select sql_variant_property(#Param, 'Precision')
Select sql_variant_property(#Param, 'Scale')
I posted that on this question.
I am asking how to tell what the sql
server types (ie varchar(25), int...)
are of what I have been given
You could then print out the type, precision (i.e. 25 if its VarChar(25)), and the scale of the parameter.
Hope that helps... :)
If you are not limited to T-SQL, and obviously you don't mind running the SPs (because SET FMTONLY ON isn't fully reliable), you definitely CAN call the SPs from, say C#, using a SqlDataReader. Then inspect the SqlDataReader to get the columns and the data types. You might also have multiple result sets, you you can also go to the next result set easily from this environment.
This code should fix you up. It returns a schema only dataset with no records. You can use this Dataset to query the columns' DataType and any other metadata. Later, if you wish, you can populate the DataSet with records by creating a SqlDataAdapter and calling it's Fill method (IDataAdapter.Fill).
private static DataSet FillSchema(SqlConnection conn)
{
DataSet ds = new DataSet();
using (SqlCommand formatCommand = new SqlCommand("SET FMTONLY ON;", conn))
{
formatCommand.ExecuteNonQuery();
SqlDataAdapter formatAdapter = new SqlDataAdapter(formatCommand);
formatAdapter.FillSchema(ds, SchemaType.Source);
formatCommand.CommandText = "SET FMTONLY OFF;";
formatCommand.ExecuteNonQuery();
formatAdapter.Dispose();
}
return ds;
}
I know this is an old question, I found it through a link from SqlDataAdapter.FillSchema with stored procedure that has temporary table. Unfortunately, neither question had an accepted answer, and none of the proposed answers were able to resolve my issue.
For the sake of brevity, if you are using SQL Server 2012 or later, using the following built-in functions will work in most situations:
sys.dm_exec_describe_first_result_set
sys.dm_exec_describe_first_result_set_for_object
However, there are some cases in which these functions will not provide any useful output. In my case, the problem was more similar to the question linked above and therefore, I believe the solution is more appropriately answered under that question. My answer can be found here.

Parameterise table name in .NET/SQL?

As the topic suggests I wish to be able to pass table names as parameters using .NET (doesn't matter which language really) and SQL Server.
I know how to do this for values, e.g. command.Parameters.AddWithValue("whatever", whatever) using #whatever in the query to denote the parameter. The thing is I am in a situation where I wish to be able to do this with other parts of the query such as column and table names.
This is not an ideal situation but it's one I have to use, it's not really prone to SQL injection as only someone using the code can set these table names and not the end-user. It is messy however.
So, is what I am asking possible?
EDIT: To make the point about SQL injection clear, the table names are only passed in by source code, depending on the situation. It is the developer who specifies this. The developer will have access to the database layer anyway, so the reason I am asking is not so much for security but just to make the code cleaner.
You cannot directly parameterize the table name. You can do it indirectly via sp_ExecuteSQL, but you might just as well build the (parameterized) TSQL in C# (concatenating the table-name but not the other values) and send it down as a command. You get the same security model (i.e. you need explicit SELECT etc, and assuming it isn't signed etc).
Also - be sure to white-list the table name.
I don't think I've ever seen this capability in any SQL dialect I've seen, but it's not an area of expertise.
I would suggest restricting the characters to A-Z, a-z, 0-9, '.', '_' and ' ' - and then use whatever the appropriate bracketing is for the database (e.g. [] for SQL Server, I believe) to wrap round the whole thing. Then just place it directly in the SQL.
It's not entirely clear what you meant about it not being a SQL injection risk - do you mean the names will be in source code and only in source code? If so, I agree that makes things better. You may not even need to do the bracketing automatically, if you trust your developers not to be cretins (deliberately or not).
You can pass the table name as a parameter like any other parameter. the key is you have to build a dynamic sql statement, which then you should consider if it's easier to build it in your app tier or in the procs.
create procedure myProc
#tableName nvarchar(50)
as
sp_executesql N'select * from ' + #tablename
fyi this code sample is from memory have a look at BOL for the proper syntax of sp_executesql.
Also this is highly sucesptible to SQL injection as you indicated is not an issue for you but anyone reading this should be very wary of accepting input from a user to generate their queries like this.
SQL query parameters can only take the place of a literal value. You cannot use a parameter for a table name, column name, list of values, or other SQL syntax. That's standard SQL behavior across all brands of database.
The only way to make the table name dynamic is to interpolate a variable into your SQL query before you prepare that string as a statement.
BTW, you're fooling yourself if you think this isn't a risk for SQL injection. If you interpolate the table name into the query dynamically, you need to use delimited identifiers around the table name, just as you would use quotes around a string literal that is interpolated from a variable.
The idea that it is not prone to SQL injection is misguided. It may be less prone to SQL injection from front end users, but it is still very much prone to SQL injection. Most attacks on databases come from inside the company being attacked, not from end users.
Employees may have grudges, they may be dishonest, they may be disgruntled, or they may just be not so bright and think that it's ok to bypass security to do whatever it is that THEY think should be done to the database.
Please see this post answer by user Vimvq1987:
MySqlParameter as TableName
Essentially you first check the table name against the schema, in which the table name is used in a parameterized fashion. Then if all is ok, the table name is legit.
Paraphrased basic idea is:
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'databasename'
AND table_name = #table;
cmd.Parameters.AddWithValue("#table",TableName);
If this returns ok with the table name, go ahead with your main query...
I would just check
select OBJECT_ID(#tablename)
the idea is to prevent injection you know it has to be table name this was if this returns a number then i would run the actual query,