How do I perform selection operations on only existing columns in temporary table? - sql

Why can't I perform selection operations after checking for column existence in a temporary table?
IF OBJECT_ID(''tempdb..#tempTable.Column'') IS NOT NULL
SELECT Column from #tempTable
--Error: Invalid column name 'Column'.
Is this error thrown because of the order of operations in SQL Server? If so, is there any way to delay the evaluation of the selection until the existence criteria is satisfied?

This is a problem that arises because the code is compiled first and then executed afterwards. The compiler checks that all columns and tables are available.
Now, the "normal" way to get around these problems is to use dynamic SQL. Something like:
IF OBJECT_ID(''tempdb..#tempTable.Column'') IS NOT NULL
exec sp_executesql N'SELECT Column from #tempTable';
But, this won't work in your case. The problem is that the #temptable is not understood in the context of the dynamic SQL.
Alas, I don't think you can do what you want with temporary tables. You could do it with a permanent table as:
IF OBJECT_ID('_tempTable.Column') IS NOT NULL
exec sp_executesql N'SELECT Column from _tempTable';
You can probably guess that when I have "temporary" tables in a non-temporary database, I use _ to distinguish them from other tables.
EDIT:
If you want to determine if a column is in a temporary table, then use logic such as this:
select *
from tempdb.sys.columns
where object_id = object_id('tempdb..#mytemptable');
(Courtesy of this answer -- which I note that I had already upvoted.)

Related

SQL: temp table "invalid object name" after "USE" statement

I do not fully understand the "USE" statement in Transact-SQL and how it affects the scope of temp tables. I have a user-defined table type in one database but not another, and I've found I need to "USE" that database in order to define a table of that type. Earlier in the query, I define a temporary table. After the "USE" statement, SSMS does not recognize the temp table as a valid object name, however I can still query from it without error.
The skeleton of my SQL query is as follows:
USE MYDATABASE1
[... a bunch of code I did not write...]
SELECT * INTO #TEMP_TABLE FROM #SOME_EARLIER_TEMP_TABLE
USE MYDATABASE2
DECLARE #MYTABLE MyUserDefinedTableType -- this table type only exists in MYDATABASE2
INSERT INTO #MYTABLE(Col1, Col2)
SELECT Col1, Col2 FROM (SELECT * FROM MYDATABASE2.dbo.SOME_TABLE_VALUED_FUNCTION(param1, param2)) T
SELECT A.*, B.Col2
FROM #TEMP_TABLE A
CROSS APPLY DATABASE2.dbo.SOME_OTHER_TABLE_VALUED_FUNCTION(#MYTABLE, A.SomeColumn) B
In the last SELECT statement, SSMS has red squiggly lines under "A.*" and "#TEMP_TABLE", however there is no error running the query.
So my question is: am I doing something "wrong" even though my query still works? Assuming the initial "USE MYDATABASE1" is necessary, what is the correct way to switch databases while still having #TEMP_TABLE available as a valid object name? (Note that moving the definition of #TEMP_TABLE to after "USE MYDATABASE2" would just shift the problem to #SOME_EARLIER_TEMP_TABLE.)
In SQL USE basically tells the query which database is the "default" database.
Temp tables can play tricks on intellisense - unless they're explicitly defined using the CREATE TABLE #MyTempTable route, intellisense doesn't really know what to do with them a lot of the time. Don't worry though - temp tables are scoped to the query.
Although I do feel it's worth pointing out: while UDTs are database specific, you can create an assembly to use across databases

Why is it not possible to set a column's alias dynamically?

I have a stored procedure and I want to pass a column alias as a parameter, something like:
SELECT u.userLoginName AS #columnName
FROM -- some JOINs
WHERE -- some conditions
where #columnName can be one of two options and it is set before the SELECT statement according to some condition.
I already know that it can be done only by dynamic SQL, but I don't understand why?
I know that the Order of execution of a Query is: FROM and JOINs -> WHERE -> GROUP BY and only then SELECT.
So if at this point I already got the result set, i.e, the finale table, why can't I just rename the column name as #columnName? What happens in the background that I miss?
This may answer your question.
A SQL result set is conceptually just like a table: it has well defined rows and columns and no ordering unless created with an explicit order by.
A SQL query is processed in two phases: it is compiled and optimized, then it is run. (Happily some databases are now starting to provide dynamic optimization as well, but the queries still go through the compilation phase.)
All information about the result set needs to be known during the compilation phase -- and that includes the resulting column names and column types. Dynamic names would prevent this from happening. They would only be known during the execution phase.
Note that this applies to parameters as identifier as well. Parameters are substituted at the beginning of the execution phase.
This is not a limitation of any particular database. It applies to all of them. I suspect that some more modern databases are implemented in a way that would allow for more dynamic naming, but I don't know of any databases that actually implement it except through dynamic SQL.
It is possible but you have to use a dynamic query.
Let assume we have the following table
Create table #TBL ([Months] VARCHAR(3), Value INT)
INSERT INTO #TBL values
('Jan',20),('Feb',12),('Jan',15),('Mar',25),
('Feb',18),('Jan',9),('Mar',10),('Jan',19)
GO
And I want to dynamically set the columns name using variable. I can use the bellow code
DECLARE #M VARCHAR(10)='Months',
#T VARCHAR(10)='Total'
-- Dynamic query to get the column name
DECLARE #qry VARCHAR(MAX)
SET #qry = 'SELECT [Months] AS '+#M+',
sum(Value) as '+#T+'
FROM #TBL
group by [Months]
DROP TABLE #TBL'
EXEC (#qry)
Note the query itself have to be dynamic

SQL - adding new column withouth effecting existing scripts

We have a table on the SQL Server 2008 which gets populated by various stored procedures. The problem is that the authors of these stored procedures used some poor choice in code and populated this table using the following syntax:
INSERT INTO persistant_table
SELECT *
FROM #temp_table_with_data
Basically they would create a #temp_table_with_data in the script and the columns would be in the same order and with the same name as they are in the persistant_table.
Now I need to add another column to this persistant_table, but if I do that, I will break all the stored procedures.
Is there a way for me to add a column to this table without breaking all the stored procedures? (In the long run, we will change the stored procedures).
Thank you
No I think.select * will pick all columns and column number should match.
I don't think it's big effort to change the line to have particular columns only or select statement to have default value for column or null and then * to store into columns sequentially. But at least 1 line to be changed
The "ALTER TABLE" is a SQL statement that allows you to make datatype changes to a database table (i.e. change datatype as well as Size columns from an existing table).
ALTER TABLE TableName ALTER COLUMN ColumnName NVARCHAR(200)
You cannot do it without affecting old scripts. This is why 'SELECT *' is not good practice. You'd better create new scripts with explicit column names like
SELECT column1, column2 ....

Find out all useful columns in a table in sql server

I have a table which has 50+ columns but only few columns are getting used. that means when any stored procedure uses that table it only refers 4-5 columns in select/where statements . rest of columns are not getting used . i just want to list down those columns that are actually getting used. one way is finding out the dependencies of a table and then go through every SP and find out which columns are getting used . but in that case i have around 30+ Sp. is there any efficient way to do it.
To use multiple columns in a procedure, you can use a code like below
create procedure sp_sample
#column_names varchar(200)
as
if #column_names='' or #column_nams is null
set #column_names='*'
exec ('select '+#column_name +' from table')
Here are some examples :
exec sp_sample #columnname='id,name'
or
exec sp_sample #columnname='id,name,telphone'
Try this:
select name from syscomments c
join sysobjects o on c.id = o.id
where TEXT like '%table_name%' and TEXT like '%column_name%'
In table_name give you table name, in column_name give the column for which you want to chck the procedure dependencies.You will get the stored procedure names as output
If you import your database as a database project using the SQL Server Data Tools, you will be able to find all references to a table or column using the "Find All References" context command. What makes this particularly useful is the accuracy: it will even find instances of SELECT * that don't mention the column explicitly, but implicitly refer to it anyway. It will also not be confused by tables or columns with similar names (finding particular instances of ID is otherwise rather problematic).
If all you want to know if a column is referenced at all, you can simply delete it and see if any "unresolved reference" errors appear in the error list -- if yes, then the column is used somewhere.

SQL Server 2005 join a number of tables in a view when some may not exist

I need to create a view, however the data is generated from an application with its own db management for tables which based on column count can create over 7 SQL Server tables for one internal table definition.
The tables all end with ['m' & number], eg devicem1, devicem2 ... devicem10
They all contain logical_name as their primary key, but you can never rely on which table will hold any other column in the internal table!
I need to create a view that joins the tables together as just device so when the application changes it doesn't mess up any stored procs I want to create.
Based on this query:
CREATE VIEW device AS
SELECT *
FROM devicem1 m1, devicem2 m2, devicem3 m3, ... devicem10 m10
WHERE m1.logical_name = m2.logical_name
AND m1.logical_name = m3.logical_name
...
AND m1.logical_name = m10.logical_name
Is there some way to join ten tables where I can ignore the fact that devicem9 & devicem10 may not exist?
With regards to the requirements of a view. The tables referenced MUST exist when the view is created. The SQL engine isn't going to allow you to create a view referencing tables that don't exist.
Considering that a view is just a stored select statement, after it's created the tables can be deleted (as long as schema-binding isn't in play); however any time you call or use the view all referenced tables must exist or it will toss an error.
Also, you CAN change the schema of referenced tables as long as it doesn't remove any fields specifically used in the view but again, if a specific column used by the view is missing any query using the view will fail.
You might have more luck getting away with what your trying to do with some creative table valued functions and dynamic sql. A table valued function is basically just a view that allows parameters and extended logic.
All in all, I would say what your describing sounds a little sketchy though.
I would periodically recreate the view based on the tables that are available.
So, if the application runs every night to create the tables, then after the app runs, check which tables are available and recreate the views.
In the end, you will have to use dynamic sql, doing something like:
declare #sql varchar(max);
select #sql = (select '(select * from '+table_name+') union all'
from information_schema.tables
for xml path (''));
set #sql = left(#sql, len(#sql) - 10);
set #sql = 'create view <whatever> as '+#sql;
exec(#sql);