By trying this
use master
go
select * into #TempTable from sys.all_views
select * from #TempTable
drop table #TempTable
exec('
select * into #TempTable2 from sys.all_views
')
/* This will give error: */
select * from #TempTable2
I realized that #TempTable2 is not accessible... so using the select into #TempTable syntax is used inside an EXEC statement means the table is auto destroyed as the exec statement is completed?
Yes.
You can see this with
exec('
select * into #TempTable2 from sys.all_views
select * from tempdb.sys.tables
')
select * from tempdb.sys.tables
You can use a ##global temporary table if you want to be able to access it later. e.g.
use master
go
declare #temptablename char(40)
set #temptablename = '[##' + cast(newid() as char(36)) + ']'
exec('
select * into ' + #temptablename + ' from sys.all_views
')
/* Do some other stuff: */
exec('
select * from ' + #temptablename)
You could create a global temp table
create table ##TempTable (
/* Structure goes here */
)
exec('insert into ##TempTable(/*Columns*/) select * from sys.all_views')
select * from ##TempTable
(If you do this, and your code might be used by multiple users, then include a SPID column in the temp table, include ##SPID in the select list, and change the final select to filter by SPID = ##SPID)
Yes you are correct. The temp table within the Exec statement is only accessible within that statement.
If you open two windows in SSMS and create a temp table in one window you won't be able to access it through the other window as it is a different connection.
However, you will be able to access it if you create a global temp table. Global temp tables are defined with a double ## instead of one.
There is an article here from SQLTeam regarding temp tables and also here from MSDN
Related
I would love to reuse a stored procedure in this situation instead of rewriting the code
IF EXISTS (EXEC [dbo].[SP_JobStop_FindJobByAll] WITH (updlock,serializable)
--IF EXISTS (SELECT * FROM [EZPassDataDB].[dbo].[JobPass] AS [o] WITH (updlock,serializable)
--WHERE [o].[jobNumber] = #jobNumber
You can load the resultset from the stored procedure into a temp table or table variable with INSERT ... EXEC, eg:
declare #jobs table(...)
insert into #jobs(...)
exec [dbo].[SP_JobStop_FindJobByAll]
if exists (select * from #jobs)
begin
. . .
end
I am writing a piece of code with the intention of searching through all databases in the server for a certain table name, however I ran into some trouble since I do not have permission to read/access all databases in the server.
I am wondering if there is a way for the query to advance if one statement is not available due to security permissions (i.e. if I have ten databases in a particular server with no access to the fourth, I would want it to run 1-2-3 and then 5-6-7-8-9-10 with returned results).
I have tried using TRY-CATCH, but I cannot seem to get the code to bypass the initial problem which is stopping when the security permissions are not available.
declare #tabell varchar(254) = 'JE' -- table name which is supposed to be
--found.
-- STEP 1: lists all available databases in the server with a row number.
drop table if exists #steg1 select name, row_number() over (order by
name) as rownumber into #steg1 from sys.databases
-- STEP 2: generates code for all databases in order to identify those
--with the table name #tabell.
drop table if exists #steg2 select 1 Ordn,'use '+name+' drop table if
exists #hitta select * into #hitta from sys.tables where name =
'''+ltrim(#tabell)+'''' as script into #steg2 from #steg1 a
where rownumber =1
union
select 2 Ordn, 'use '+name+' insert into #hitta select * from sys.tables
where name = '''+ltrim(#tabell)+'''' from #steg1 a
where rownumber >1
union
select 3 Ordn,'select * from #hitta' as x
-- STEP 3: concatenate the generated code into a single string.
declare #string varchar(max)
select #string = concat(#string + ' ', '')+ script from #steg2
drop table if exists #steg3 select #string as string into #steg3
-- STEP 4: exec the code concatenated in the previous step.
declare #cmd varchar(max)
begin
set #cmd = (select string from #steg3)
exec (#cmd)
end
Getting the error message: Msg 916, level 14, state 1, stating that the user cannot access the database under the current security context.
I managed to solve my issue using has_dbaccess(database), below you can see how I incorporated it into the code.
declare #tabell varchar(254) = 'JE' -- table name which is
supposed to be found.
-- STEP 1: lists all available databases in the server with a row number.
drop table if exists #steg1 select name, row_number() over (order by name) as rownumber
into #steg1 from (SELECT name, has_dbaccess(name) access FROM sys.databases) a where
access = 1
-- STEP 2: generates code for all databases in order to identify those with the table
--name #tabell.
drop table if exists #steg2 select 1 Ordn,'use '+name+' drop table if exists #hitta
select name as [Table], cast('''+name+'''as varchar(max)) as [Databas] into #hitta from
sys.tables where name = '''+ltrim(#tabell)+'''' as script into #steg2 from #steg1 a
where rownumber =1
union
select 2 Ordn, 'use '+name+' insert into #hitta select name as [Table],
cast('''+name+'''as varchar(max)) as [Databas] from sys.tables where name =
'''+ltrim(#tabell)+'''' from #steg1 a
where rownumber >1
union
select 3 Ordn,'select * from #hitta' as x
-- STEP 3: concatenate the generated code into a single string.
declare #string varchar(max)
select #string = concat(#string + ' ', '')+ script from #steg2
drop table if exists #steg3 select #string as string into #steg3
-- STEP 4: exec the code concatenated in the previous step.
declare #cmd varchar(max)
begin
set #cmd = (select string from #steg3)
exec (#cmd)
end
I have this two szenarios (strongly simplified).
- When executing (F5) everything is fine.
- When showing the estimated execution plan (Ctrl-L) there is an error: "Invalid object name '#t1'."
Is there any way to use the first szenario (select into) and still being able to "Ctrl-L" and "F5" the code? Something like "delayed validation" in SSIS?
--first szenario: select into
if object_id ('tempdb..#t1') is null begin
select 1 c1 into #t1;
select * from #t1;
drop table #t1;
end
--second szenario: insert
if object_id ('tempdb..#t2') is null begin
create table #t2 (c1 int);
insert #t2 select 2;
select * from #t2;
drop table #t2;
end
I am trying to create a function in SQL SERVER which I can use to compare two tables, to check if they are identical. I do that with two excepts.
The Tables are supposed to be exactly the same, with the same data formats and column names as well as all values identical in both tables. This will be a manual check, so if differences are there, a thrown error is not a problem. The aim is just to see if two approaches of creating the tables leads to the same tables.
I am really new to functions in SQL, so I am not sure how to solve the problem.
I want to pass both tables as parameters to the function, to get something like this:
CREATE FUNCTION DIFFERING_ROWS
(#TABLE1, #TABLE2)
RETURNS TABLE
AS
RETURN (
SELECT *, 'A_not_B' as [Difference] FROM #TABLE1
except
SELECT *, 'A_not_B' as [Difference] FROM #TABLE2
union all
SELECT *, 'B_not_A' as [Difference] FROM #TABLE2
except
SELECT *, 'B_not_A' as [Difference] FROM #TABLE1
)
END
How is this implemented correctly?
Can anybody help me?
You cannot do this in a function. The only way you can pass table names as parameters is to use Dynamic SQL, and Dynamic SQL is not allowed in functions. You CAN do it with a stored procedure.
You can create this stored procedure that counts if the tables have the same column_names:
CREATE PROCEDURE checkEqualTables
#table1 varchar(100),
#table2 varchar(100)
AS
BEGIN
DECLARE #xCount int;
(SELECT #xCount = COUNT(*) from (SELECT column_name FROM information_schema.COLUMNS WHERE table_name=#table1) base
where column_name not in (SELECT column_name FROM information_schema.COLUMNS WHERE table_name=#table2))
IF(#xCount <= 0)
print 'Tables are equal!';
ELSE
print 'Tables are not equal!'
END
Ok I took the information from the answers and comments and researched about how to put this into procedures, and this is what I built:
I think this does what I want:
CREATE PROCEDURE checkEqualTables
#table1 nvarchar(100),
#table2 nvarchar(100)
AS
BEGIN
DECLARE #SQL nvarchar(max);
SET #SQL = 'SELECT * FROM ' + #TABLE1 +
'except
SELECT * FROM ' + #TABLE2 +
'union all
SELECT * FROM ' + #TABLE2 +
'except
SELECT * FROM ' + #TABLE1
EXECUTE sp_executesql #SQL
END
I'm using MSQL 2005. I have 2 table.A and B
Table A
- ID DOVKOD
- 1 KURSATIS
Table B
- ID KURALIS KURSATIS
- 1 2,2522 2,2685
- 2 2,4758 2,4874
Table A has only 1 record
When I execute Select (Select DOVKOD from Table A) from Table B I want to get same result as Select KURSATIS from Table B
I am gonna use it in a view. How can I do that. Thanks..
You can simply use a CASE expression:
SELECT CASE WHEN (SELECT DOVKOD FROM A) = 'KURSATIS' THEN KURSATIS
ELSE KURALIS
END
FROM B
SQL Fiddle Demo here
You must use Dynamic TSQL
SELECT #column=DOVKOD from Table A
EXEC ('Select ' + #column + ' from Table B')
If I understood you right then in table A you have the name of the column that you want to return. Then your solution is bad at all. I'll rather do something like that:
CREATE TABLE #TableA
(
ID INT, DOVKOD VARCHAR(100)
);
INSERT INTO #TableA VALUES (1, 'KURSATIS');
CREATE TABLE #TableB
(
ID INT, Value DECIMAL (18,2),Name VARCHAR(100)
);
INSERT INTO #TableB VALUES (1, 2.2522 , 'KURALIS');
INSERT INTO #TableB VALUES (2, 2.4758 , 'KURSATIS');
SELECT #TableB.* FROM #TableB JOIN #TableA ON #TableA.DOVKOD = #TableB.Name
The only way how to do this in MySQL is using Prepared statements. Dynamic pivot tables (transform rows to columns) is a good article about this.
SET #sql = NULL;
Select DOVKOD INTO #sql
FROM from Table A;
SET #sql = CONCAT('SELECT ', #sql, 'FROM Table B');
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;