How to generate temp table columns and datatypes automatically via script - sql

I create temp tables quite often in SQL and I am looking into a way to generate the column names and datatypes automatically for the table definition so I don't have to look them all up everytime.
For example I run:
SELECT CustomerID
ClientID,
FirstName
LastName
INTO #Test
From dbo.Customer
To initially setup the temp table with the appropriate columns and data I need. Once I get that all done, I then go back in and take out the INTO statement and write the following:
CREATE TABLE #Test
(
...
...
);
I want to find a way to auto generate the column names and datatypes from the initial creation of the temp table. Right now, since I am initially inserting into an automatically created temp table, I use this:
EXEC tempdb..sp_help '#Test';
This gives me everything I need without having to look all the column datatypes up, but I wanted to know if there was a way to just auto gen the column names off of something like this. So the auto gen would generate:
CustomerID int,
ClientID int,
FirstName varchar(50),
LastName varchar(50)
This would allow me to just copy and paste this into my create table statement.

this might give you a start:
DECLARE #viewname VARCHAR(50);
SET #viewname ='tableorviewname';
SELECT c.name + ' '+ t.name +
case t.name
WHEN 'varchar' THEN '('+CAST(c.max_length AS VARCHAR(3) )+'),'
ELSE ','
end
FROM sys.columns c
INNER JOIN sys.types AS t ON c.system_type_id = t.system_type_id
WHERE object_id = (SELECT object_id from sys.objects where name = #viewname)
ORDER BY c.column_id
EDIT: TEMP TABLES:
temp tables are slightly different, for instance this works in sql 2008 for a temp table named #tv_source
DECLARE #viewortablename VARCHAR(50);
SET #viewortablename ='tempdb..#tv_source';
SELECT c.name + ' '+ t.name +
case t.name
WHEN 'varchar' THEN '('+CAST(c.max_length AS VARCHAR(3) )+'),'
ELSE ','
end
FROM tempdb.sys.columns c
INNER JOIN sys.types AS t ON c.system_type_id = t.system_type_id
WHERE object_id = object_id(#viewortablename)
ORDER BY c.column_id
NOTES: this gives a comma separated list, but did NOT attempt to remove that last comma, it gives only a list, which you would likely want to put on a string and manipulate, etc. then use as a dynamic sql or somthing. Still, it should give you a start on what you wish to do.
NOTE for to others, sql 2000 would not display the lengths properly for instance on a varchar(45), it would just list the varchar part and I did not attempt to rework that for this question.

SELECT
', ['+ac.name+'] '+Type_Name(User_type_id)+
CASE WHEN Type_Name(User_type_id) = 'Decimal'
THEN +'('+CONVERT(Varchar(4),ac.Precision)+','+CONVERT(Varchar(4),ac.Scale)+')'
WHEN Type_Name(User_type_id) IN
('tinyint','smallint','int','real','money','float','numeric','smallmoney','DateTime')
THEN ''
ELSE +'('+CONVERT(Varchar(4),ac.Max_Length)+')'
END AS TableColumn
FROM Tempdb.sys.all_columns AS ac
INNER JOIN Tempdb.Sys.SysObjects AS so
ON so.ID = ac.Object_ID
WHERE 1 = 1
AND so.Name = '##YourTempTableGoesHere'

...I've created a function that can output the list of columns and datatypes, if the object is a table, if that is something that would be useful for you?
CREATE FUNCTION [dbo].[fnDiscoverColumns]
( #PObjectName NVARCHAR(300) )
RETURNS #Data TABLE ( ColumnList NVARCHAR(350) )
AS
BEGIN
DECLARE #PObjectID TABLE ( [object_id] INT )
INSERT #PObjectID ( [object_id] )
SELECT [object_id] FROM sys.objects AS O WHERE O.name = #PObjectName AND O.type = 'U'
DECLARE #PObjectDetails TABLE ( [RowNo] INT,[ColumnName] NVARCHAR(300),[XType] INT,[DataType] NVARCHAR(100),[system_type_id] INT,[user_type_id] INT,[MaxLength] NVARCHAR(5),[Precision] INT,[Scale] INT,[ColumnList] NVARCHAR(300) )
INSERT #PObjectDetails ( [RowNo],[ColumnName],[XType],[DataType],[system_type_id],[user_type_id],[MaxLength],[Precision],[Scale],[ColumnList] )
SELECT DISTINCT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS 'RowNo',
C.name AS 'ColumnName',
T.xtype AS 'XType',
UPPER(T.name) AS 'DataType',
C.system_type_id,
C.user_type_id,
CASE WHEN C.max_length < 0 THEN 'MAX' ELSE CAST(C.max_length AS VARCHAR) END AS 'MaxLength',
C.precision AS 'Precision',
C.scale AS 'Scale',
CASE
WHEN [XType] IN (34,35,36,40,48,52,56,58,59,60,61,62,98,99,104,122,127,189,240,241) THEN QUOTENAME(C.name) +' '+ UPPER(T.name) +','
WHEN [XType] IN (106,108) THEN QUOTENAME(C.name) +' '+ UPPER(T.name) +'('+ CAST([Precision] AS VARCHAR) +','+ CAST(C.scale AS VARCHAR) +'),'
WHEN [XType] IN (41,42,43,165,167,173,175,231,239) THEN QUOTENAME(C.name) +' '+ UPPER(T.name) +'('+ CASE WHEN C.max_length < 0 THEN 'MAX' WHEN C.max_length > 1 THEN CAST(C.max_length / 2 AS VARCHAR) ELSE CAST(C.max_length AS VARCHAR) END +'),' ELSE NULL END AS 'ColumnList'
FROM sys.all_columns AS C
JOIN systypes AS T ON C.system_type_id = T.xusertype
WHERE C.object_id = (SELECT * FROM #PObjectID) --373576369
--Return column names and data types
INSERT #Data
SELECT 'CREATE TABLE #ColumnsList ('
INSERT #Data
SELECT
CASE WHEN C.RowNo = (SELECT MAX(RowNo) FROM #PObjectDetails) THEN LEFT(C.ColumnList, ABS(LEN(C.ColumnList + ',') - 2)) ELSE C.ColumnList END AS 'GeneratedColumns'
FROM #PObjectDetails AS C
INSERT #Data
SELECT ')'
RETURN
END
GO
Once committed to the database, run it like this:
SELECT * FROM [dbo].[fnDiscoverColumns] ('ExecutionLogStorage') --name of table
This should give you an output like this:
CREATE TABLE #ColumnsList (
[LogEntryId] BIGINT,
[InstanceName] NVARCHAR(38),
[ReportID] UNIQUEIDENTIFIER,
[UserName] NVARCHAR(260),
[ExecutionId] NVARCHAR(64),
[RequestType] TINYINT,
[Format] NVARCHAR(26),
[Parameters] NTEXT,
[ReportAction] TINYINT,
[TimeStart] DATETIME,
[TimeEnd] DATETIME,
[TimeDataRetrieval] INT,
[TimeProcessing] INT,
[TimeRendering] INT,
[Source] TINYINT,
[Status] NVARCHAR(40),
[ByteCount] BIGINT,
[RowCount] BIGINT,
[AdditionalInfo] XML
)

Related

Dynamic SQL stored procedure not populating temporary table

I am using a stored procedure with one parameter (#tablename) to generate a table of attributes about the table named via the parameter.
I call the stored procedure as follows
EXEC sp_Schema_Presentation #tablename = 'UserID'
And run the stored procedure (at the bottom of this post).
I have created a #DynamicSQL string in order to use my #tablename parameter. However, the SELECT statement, in which it's used, also creates the #TEMP table.
The rest of the query uses this #TEMP table so I DECLARE its structure at the top.
However, when I run the stored procedure, the #TEMP table is empty
If I hard code the #tablename, the query will work. Any ideas how I can fix this?
Thanks
CREATE TABLE #TEMP
(
SampleKey nvarchar(MAX),
SampleData nvarchar(MAX)
)
DECLARE #DynamicSQL NVARCHAR(MAX)
SET #DynamicSQL = N'SELECT B.*
INTO dbo.#TEMP
FROM (
SELECT * FROM ' + #Tablename + N' ORDER BY 1 DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY
) A
CROSS APPLY (
SELECT [Key] AS SampleKey
,Value AS SampleData
FROM OpenJson( (SELECT A.* FOR JSON Path, Without_Array_Wrapper,INCLUDE_NULL_VALUES ) )
) B'
Full stored procedure in SQL Server 2016:
ALTER PROCEDURE [dbo].[sp_Schema_Presentation]
#TableName nvarchar(MAX)
AS
BEGIN
CREATE TABLE #TEMP
(
SampleKey nvarchar(MAX),
SampleData nvarchar(MAX)
)
DECLARE #DynamicSQL NVARCHAR(MAX)
SET #DynamicSQL = N'SELECT B.*
INTO dbo.#TEMP
FROM (
SELECT * FROM ' + #Tablename + N' ORDER BY 1 DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY
) A
CROSS APPLY (
SELECT [Key] AS SampleKey
,Value AS SampleData
FROM OpenJson( (SELECT A.* FOR JSON Path, Without_Array_Wrapper,INCLUDE_NULL_VALUES ) )
) B'
DECLARE #Columns as NVARCHAR(MAX)
SELECT #Columns = COALESCE(#Columns + ', ','') + QUOTENAME(COLUMN_NAME)
FROM
(
SELECT COLUMN_NAME FROM PRESENTATION_PP.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N''' + #TableName + '''
) AS B
EXECUTE sp_executesql #DynamicSQL
SELECT a.COLUMN_NAME,
CASE WHEN a.COLUMN_NAME LIKE '%[_]_key' THEN a.COLUMN_NAME
ELSE REPLACE(a.COLUMN_NAME,'_',' ') END AS DISPLAY_NAME,
a.DATA_TYPE, COALESCE(a.CHARACTER_MAXIMUM_LENGTH, a.NUMERIC_PRECISION) AS SIZE,
CASE WHEN NUMERIC_SCALE IS NULL THEN 0
ELSE NUMERIC_SCALE END AS SCALE,
a.IS_NULLABLE AS NULLABLE,
CASE WHEN i.is_primary_key IS NOT NULL THEN 'YES'
ELSE 'NO' END AS PK,
#TEMP.SampleData
FROM PRESENTATION_PP.INFORMATION_SCHEMA.COLUMNS a
LEFT JOIN
sys.columns c ON a.COLUMN_NAME = c.name
LEFT JOIN
sys.index_columns ic ON ic.object_id = c.object_id AND ic.column_id = c.column_id
LEFT JOIN
sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id
LEFT JOIN
#TEMP ON a.COLUMN_NAME COLLATE SQL_Latin1_General_CP1_CI_AI = #TEMP.SampleKey COLLATE SQL_Latin1_General_CP1_CI_AI
WHERE TABLE_NAME = #TableName AND c.object_id = OBJECT_ID(#TableName)
SELECT * FROM #TEMP
DROP TABLE #TEMP
END
Create the #Temp table first, and then INSERT INTO not Select ... Into #Temp
CREATE TABLE #TEMP (SampleKey nvarchar(MAX), SampleData nvarchar(MAX))
DECLARE #DynamicSQL NVARCHAR(MAX)
SET #DynamicSQL = N'
Insert Into #Temp
SELECT B.*
FROM (
SELECT * FROM ' + #Tablename + N' ORDER BY 1 DESC
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY
) A
CROSS APPLY (
SELECT [Key] AS SampleKey
,Value AS SampleData
FROM OpenJson( (SELECT A.* FOR JSON Path, Without_Array_Wrapper,INCLUDE_NULL_VALUES ) )
) B
'
Exec(#DynamicSQL)
Select * from #Temp

Stored procedure for inserting default value based on column type

I'm trying to figure out how to create a stored procedure which takes a table as input and then inserts values in all of the columns based on the column type.
For example: the table Dim.Name has two columns; the first is ID which is an int and the second is Name which is of type nvarchar:
ID(int)
Name(nvarchar)
I'm trying to figure out how to create a stored procedure that will take the table as a input and insert '-1' for all the int columns and 'Unknown' for all the nvarchar columns.
So the desired result would be
dbo.usp_InsertData(Dim.Name)
ID(int)
Name(nvarchar)
-1
Unknown
You can build a dynamic INSERT using sys.columns
Exactly why you would want to do this is another question.
CREATE OR ALTER PROCEDURE WeirdInsert
#schema sysname,
#table sysname
AS
DECLARE #sql nvarchar(max) = (
SELECT '
INSERT ' + QUOTENAME(#schema) + '.' + QUOTENAME(#table) + '
(' + STRING_AGG(QUOTENAME(c.name), ', ') + ')
VALUES (' + STRING_AGG(
CASE WHEN c.system_type_id IN (34,35,99,167,167,175,231,239)
THEN '''Unknown'''
WHEN c.system_type_id IN (48,52,56,59,60,62,106,108,122,127)
THEN '-1'
ELSE 'DEFAULT'
END , ', ')
+ ');'
FROM sys.columns c
JOIN sys.tables t ON t.object_id = c.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE t.name = #table
AND s.name = #schema
);
EXEC sp_executesql #sql; -- can also pass parameters
SQL Fiddle

Dynamic SQL Server Query loop through schema find primary key duplicate

EDIT: There seems to be some confusion around the create table statements. These are there solely as a demonstration of what tables *might come in to our synapse instance, not as actual code that will run. The important part of the question is contained in the latter half.
I am trying to create a stored procedure that loops through every table in a supplied schema and outputs the count of duplicate primary key rows for each table. Assume that the data is being supplied from elsewhere and the primary keys are not being enforced. For example I may have three tables in the stack schema:
CREATE TABLE stack.table1(
id int,
name NVARCHAR(MAX),
color NVARCHAR(20)
PRIMARY KEY (id))
INSERT INTO stack.table1 VALUES(1,'item1','yellow')
(2,'item2','blue')
(2,'item2','blue')
CREATE TABLE stack.table2(
id int,
name NVARCHAR(MAX),
size NVARCHAR(1)
PRIMARY KEY (id,size))
INSERT INTO stack.table2 VALUES(1,'item1','L')
(2,'item2','M')
(3,'item2','S')
CREATE TABLE stack.table3(
id int,
name NVARCHAR(MAX),
weight NVARCHAR(20)
PRIMARY KEY (id))
INSERT INTO stack.table1 VALUES(1,'item1','200lb')
(2,'item2','150lb')
(3,'item2','125lb')
I want to supply a variable to a stored procedure to indicate the schema (in this case 'stack') and have that procedure spit out a table with the names of the tables in the schema and the counts of duplicate primary key rows. So in this example a stored procedure called 'loopcheck' would look like this:
Query:
EXEC loopcheck #schema = 'stack'
Output:
table
duplicate_count
table1
1
table2
0
table3
0
I am using an Azure Synapse instance so there are several functions that are not available (such as FOR XML PATH and others.) Since each table may have a single column primary key or a composite primary key I need to join to the system provided tables to get primary key info. My general idea was like so:
CREATE procedure loopcheck #schema= NVARCHAR(MAX)
AS
BEGIN
create table #primarykey(
SCHEMA_NAME nvarchar(400),
TABLE_NAME nvarchar(500),
COLUMN_NAME nvarchar(500)
)
insert into #primarykey
select l.TABLE_SCHEMA,
l.TABLE_NAME,
l.COLUMN_NAME
from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE l
inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS t on l.constraint_Name = t.CONSTRAINT_NAME
where
l.table_schema = #schema
CREATE TABLE #groupBy2(
TABLE_NAME nvarchar(50),
groupby nvarchar(200)
)
INSERT INTO #groupBy2
SELECT TABLE_NAME, STRING_AGG(CONVERT(NVARCHAR(max), COLUMN_NAME), ',') as groupby
FROM #primarykey
GROUP BY TABLE_NAME
DECLARE #currentTable NVARCHAR(MAX)=''
DECLARE #currentGroup NVARCHAR(MAX)=''
create table #work4(
TABLE_NAME nvarchar(400),
COUNT int)
DECLARE #final NVARCHAR(MAX)=
'INSERT INTO #work4
SELECT '+#currentTable+', COUNT(*) FROM '+#currentTable+'GROUP BY'+#currentGroup
WHILE (SELECT COUNT(*) FROM #groupby2)>0
BEGIN
SET #currentTable =(SELECT TOP 1 TABLE_NAME FROM #groupby2 ORDER BY TABLE_NAME)
SET #currentGroup =(SELECT TOP 1 groupby FROM #groupby2 ORDER BY TABLE_NAME)
exec #final
DELETE #groupby2 where TABLE_NAME =#currentTable
END
END
This code gives me an error:
Incorrect syntax near 'SELECT'
but doesn't give me the actual line it has the error on.
Your primary issue was syntax errors: parameter declaration should not have = between name and type name, and missing spaces in the dynamic SQL.
Also
A schema name (or any object) can be up to nvarchar(128), you can use the alias sysname
You don't need to do any loops or use temp tables, you can build one big dynamic statement to execute
CREATE procedure loopcheck
#schema sysname
AS
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
TableName = ' + QUOTENAME(t.name, '''') + ',
IndexName = ' + QUOTENAME(i.name, '''') + ',
Duplicates = COUNT(*)
FROM (
SELECT 1 n
FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' t
GROUP BY ' + cols.agg + '
HAVING COUNT(*) > 1
) t
'
AS nvarchar(max)), 'UNION ALL')
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
AND s.name = #schema
JOIN sys.indexes i ON i.object_id = t.object_id
AND i.is_unique = 1
CROSS APPLY (
SELECT STRING_AGG('t.' + QUOTENAME(c.name), ', ')
FROM sys.index_columns ic
JOIN sys.columns c ON c.column_id = ic.column_id AND c.object_id = t.object_id
WHERE ic.index_id = i.index_id
AND ic.object_id = i.object_id
AND ic.is_included_column = 0
) cols(agg)
);
PRINT #sql; -- for testing
EXEC sp_executesql #sql;
db<>fiddle
I feel like there might be a slightly more efficient method using GROUPING SETS in cases where there are multiple unique indexes/constraints on a single table, but I'll leave that to you.

Select Into #Temp not working with a PIVOT

I've got this dynamically created mess that essentially takes all fields in a table and compares two records against each other:
DECLARE #ID1 AS VarChar(3)
DECLARE #ID2 AS VarChar(3)
Set #ID1 = '42'
Set #ID2 = '600'
-- Where clause params
DECLARE #whereClauseParam VARCHAR(MAX) = '['+#ID1+'] <> ['+#ID2+']'
--***************************************--
--******** tblSQLAdminInventory ********--
--***************************************--
--Get the Fields required for the initial pivot
DECLARE #AIFields VARCHAR(MAX)= '';
DECLARE #AIFields2 VARCHAR(MAX)= '';
SELECT #AIFields+=QUOTENAME(t.name)+', '
FROM sys.columns AS t
WHERE t.object_id = OBJECT_ID('tblSQLAdminInventory')
AND t.name <> 'TransID'
--AND t.system_type_id = '56';
SELECT #AIFields2+='Convert(VarChar(250), '+QUOTENAME(t.name)+') AS '+ QUOTENAME(t.name) +', '
FROM sys.columns AS t
WHERE t.object_id = OBJECT_ID('tblSQLAdminInventory')
AND t.name <> 'TransID'
--AND t.system_type_id = '56';
--56 (Int)
--61 (DateTime)
--104 (Bit)
--167 (VarChar)
--231 (NVarChar)
-- Get the KeyId's with alias added
DECLARE #AIkeyIDs VARCHAR(MAX),
#AIkeyIDs1 VARCHAR(MAX);
SELECT #AIkeyIDs = COALESCE(#AIkeyIDs + ',','') + QUOTENAME(t.TransID) + ' AS [KeyID_' + CAST(t.TransID AS VARCHAR(10)) + ']',
#AIkeyIDs1 = COALESCE(#AIkeyIDs1 + ',','') + QUOTENAME(t.TransID)
FROM tblSQLAdminInventory AS t
WHERE TransID IN (#ID1, #ID2);
--Generate Dynamic SQL
DECLARE #AISQL2 VARCHAR(MAX)= 'SELECT Value AS FieldName, ';
SELECT #AISQL2+=#AIkeyIDs+'
FROM
(SELECT TransID, Value, FieldName
FROM
(SELECT TransID, '+SUBSTRING(#AIFields2, 1, LEN(#AIFields2)-1)+'
FROM tblSQLAdminInventory) p
UNPIVOT
(FieldName FOR Value IN
('+SUBSTRING(#AIFields, 1, LEN(#AIFields)-1)+')
)AS unpvt) AS SourceTable
PIVOT
(
MAX(FieldName)
FOR TransID IN ('+#AIkeyIDs1+')
) AS PivotTable
WHERE '+#whereClauseParam
EXECUTE(#AISQL2);
The problem is, it won't seem to let me put the results in a temp table. I tried using this code but it keeps telling me the #Temp1 object doesn't exist:
SELECT #AISQL2+=#AIkeyIDs+'
INTO #Temp1
FROM
(SELECT TransID, Value, FieldName
FROM
(SELECT TransID, '+SUBSTRING(#AIFields2, 1, LEN(#AIFields2)-1)+'
FROM tblSQLAdminInventory) p
UNPIVOT
(FieldName FOR Value IN
('+SUBSTRING(#AIFields, 1, LEN(#AIFields)-1)+')
)AS unpvt) AS SourceTable
PIVOT
(
MAX(FieldName)
FOR TransID IN ('+#AIkeyIDs1+')
) AS PivotTable
WHERE '+#whereClauseParam
What am I doing wrong?
You're using dynamic SQL. The EXECUTE statement starts a whole new scope and that temporary table isn't available in that scope.
There are several work-arounds, like using a permanent table that you clear out or using a global temporary table, but they all have their own pitfalls.

Query tables ordered by having most number of records

i have a task to cleanup the database from useless records. in the planning, first i have to check what are the tables that holds the most number of records. i know i can check them one by one manually, but the table list is too long and am thinking it's not too wise to run through them manually before checking if there is any automatic query that can do the job.
manually, i can query each table using this query:
select count(*) from <table_name>
even using sysobjects, i could not find the current Number Of Records
select * from sysobjects s where type='U' and name = '<table_name>'
anybody has an idea?
An approximation for the number of rows in each table is kept as part of index statistics, and is stored in the yourDB..systabstats Assuming you run update statistics on a regular basis, here's how you can get the information.
SELECT o.name, t.rowcnt
FROM sysobjects o, systabstats t
WHERE o.id = t.id
AND t.rowcnt > 0 --ignore 0 row entries
AND o.name not like "sys%" --exclude system tables
ORDER BY t.rowcnt DESC
This works in T-SQL. Not sure if it will work in Sybase...
CREATE TABLE #RecCounts (TableName varchar(100), RecCount int)
SELECT object_id INTO #Processed FROM sys.tables WHERE name = '(no such table)'
DECLARE #TableId int, #TableName varchar(255), #TableSchema varchar(100), #CountSQL varchar(255)
SELECT #TableId = MIN(object_id) FROM sys.tables WHERE type = 'U'
AND object_id NOT IN (SELECT object_id FROM #Processed)
SET #TableId = ISNULL(#TableId, -1)
WHILE #TableId > -1 BEGIN
PRINT #TableId
SELECT #TableName = name FROM sys.tables WHERE type = 'U' AND object_id = #TableId
SELECT #TableSchema = s.name, #TableName = t.name
FROM sys.Tables t
INNER JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE t.object_id = #TableId
SET #CountSQL = 'DECLARE #RecCount int
SELECT #RecCount = COUNT(*) FROM ' + #TableSchema + '.' + #TableName + '
INSERT INTO #RecCounts (TableName, RecCount) VALUES (''' + #TableName + ''', #RecCount)'
PRINT #CountSQL
EXEC(#CountSQL)
INSERT INTO #Processed (object_id) VALUES(#TableId)
SELECT #TableId = MIN(object_id) FROM sys.tables WHERE type = 'U'
AND object_id NOT IN (SELECT object_id FROM #Processed)
END
SELECT * FROM #RecCounts