Create table that contains table_name and max_date of each table - sql

I have a table with only one column -Table_Name, that contains all table names in the database.
How can I create a process that will create another table with all of the names from the table above (Table_Name) and a second column with the max update date (Max_Update_Date) of each table ?
**Need to pull the value out from the column Update_Date from the tables themselves
Here is what I got so far -
DROP TABLE IF EXISTS #TempTable
select row_number()over (order by a.Table_Name) as rn, a.Table_Name, s.modify_date
into #TempMasterTable
from API_Tables a left join sys.tables s
on s.name=a.Table_Name
select * from #TempTable
declare #counter int,
#table nvarchar(50);
set #counter=(select top 1 rn from #TempTable order by rn desc)
while #counter>0
begin
set #table=( select table_name
from #TempTable
where #counter=rn);
update #TempTable
set modify_date=(select max([update_date]) from #table)
set #counter=#counter-1;
end

You can't directly use a table name from parameter in update statement. need to use the dynamic SQL. I have modified based on your requirement
DECLARE
#id INT
,#tablename VARCHAR(200)
,#TSQL NVARCHAR(MAX)
DROP TABLE IF EXISTS #TempMasterTable
SELECT ROW_NUMBER() OVER (ORDER BY Table_Name) AS Id
,Table_Name AS TableName
,ST.modify_date
INTO #TempMasterTable
FROM API_Tables APT
LEFT JOIN sys.tables ST
ON ST.name = APT.Table_Name
DECLARE tablename_cursor CURSOR FOR
SELECT Id,TableName
FROM #TempMasterTable
OPEN tablename_cursor
FETCH NEXT FROM tablename_cursor INTO #id,#tablename
WHILE ##FETCH_STATUS = 0
BEGIN
SET #TSQL = 'UPDATE #TempMasterTable SET modify_date = (SELECT MAX([update_date]) FROM '+#tablename+') WHERE Id ='+#id
EXEC( #TSQL)
FETCH NEXT FROM tablename_cursor INTO #id,#tablename
END
CLOSE tablename_cursor
DEALLOCATE tablename_cursor

Related

Query to get max insert stamp of each table from a database

Objective:
I would like to know how recent a table was updated on a daily basis.
Is there a more a efficient way to query the max(insert_stamp) of each table in a db without having to do this:
select 't1' as table_name, max(insert_stamp) as latest_update
from t1
union all
select 't2' as table_name, max(insert_stamp)
from t2
...
or something along the lines of:
use products
go
SELECT st.name as table_name, ... (column name with insert_stamp)
from sys.tables st
where st.name not like ('staging%')
group by st.name
order by 1
I actually really hate this but this is something I just typed up real fast.
I hate using dynamic sql for stuff like this but sometimes you have no choice
This probably couldve been a cursor or a recursive cte
also, ew gross loops.
However this will get you what you want.
SELECT
name
, ROW_NUMBER() OVER (Order by name asc) as ROWID
INTO #tmp
FROM sys.Objects WHERE type='U'
declare #count int, #rowMax int, #date datetime, #sql varchar(max);
set #count = 1
set #rowMax =(SELECT Max(ROWID) FROM #tmp);
CREATE TABLE #dates
(
name varchar(255)
, timestamp datetime
)
WHILE #count <= #RowMax
BEGIN
set #sql = 'SELECT MAX(insert_stamp) FROM '+(SELECT Name FROM #tmp WHERE ROWID=#count)+';'
exec sp_executesql #sql, N'#x datetime out', #date out
INSERT INTO #dates SELECT (SELECT Name FROM #tmp WHERE ROWID=#count), #date
set #count=#count+1
END
SELECT * FROM #dates

How to retrieve a column name from a table that is stored as a value in another table

I'm pretty new to sql so any help will be much appreciated
I have a table containing a list of table names in a column of a table and I need to retrieve a column called [Last Refreshed] from all the tables listed. The tables all have different structures but they all have the [Last Refreshed] Column. I have managed to insert the tablenames into a sql variable but up to this point I am kind of stuck.
I hope I managed to explain what I need but I have attached my code as well.
Declare #tables nvarchar(max)
Declare #sql nvarchar(max)
Declare #cnt int
DECLARE #Counter int
SET #Counter = 1
DECLARE #RowCount INT
SET #RowCount = (SELECT COUNT(*)
FROM (
SELECT * FROM TABLE_LIST1
UNION
SELECT * FROM TABLE_LIST2) data )
DROP TABLE #DB_DUMMY
CREATE TABLE #DB_DUMMY (
[TABLENAME] VARCHAR(512),
[LAST_REFRESHED] VARCHAR(533)
);
WHILE ( #Counter <= #RowCount)
BEGIN
SELECT #tables = FinalTable, #cnt = Row_num from (
SELECT FinalTable , ROW_NUMBER() OVER(ORDER BY FinalTable DESC) AS Row_num
FROM (
SELECT FinalTable FROM TABLE_LIST1
UNION
SELECT FinalTable FROM ABLE_LIST2) data
group by FinalTable) a
where Row_num = #Counter
--This part doesnt work
INSERT INTO #DB_DUMMY(TABLENAME,LAST_REFRESHED)
SELECT #tables , [Last Refreshed] from #tables
SET #Counter = #Counter + 1
END
exec(#sql)
I expect to see a list of tablenames as well as the last refresh in the temporary table #DB_DUMMY
i add the [Last Refreshed] column to my tables and write this query and give me the correct answer
DROP TABLE IF EXISTS #DB_DUMMY
CREATE TABLE #DB_DUMMY (
[TABLENAME] VARCHAR(512),
[LAST_REFRESHED] VARCHAR(533)
);
DECLARE #COMMAND NVARCHAR(MAX)
SELECT #COMMAND = STRING_AGG(' INSERT INTO #DB_DUMMY SELECT DISTINCT '+CHAR(39)+T.name+CHAR(39)+',['+C.name+'] FROM '+S.name+'.'+T.name + ' GO', CHAR(13)+CHAR(10))
FROM sys.all_columns C
INNER JOIN sys.tables T ON C.object_id = T.object_id
INNER JOIN sys.schemas S ON T.schema_id = S.schema_id
WHERE C.name = 'Last Refreshed'
PRINT(#COMMAND)
EXEC(#COMMAND)
SELECT * FROM #DB_DUMMY
two first line with IF EXISTS is new syntax in sql server 2017
Just a suggestion You could use a INSERT SELECT
INSERT INTO #DB_DUMMY(TABLENAME,LAST_REFRESHED)
SELECT 'TABLE_LIST1', LAST_REFRESHED
FROM TABLE_LIST1
UNION ALL
SELECT 'TABLE_LIST2', LAST_REFRESHED
FROM TABLE_LIST2
UNION ALL
.....
SELECT 'TABLE_LISTN', LAST_REFRESHED
FROM TABLE_LISTN
Try something like this:
declare cur cursor for Select TableName From TABLE_LIST
declare #tablename nvarchar(max)
declare #sqlstring nvarchar(max)
open cur
fetch next from cur into #tablename
while ##fetch_status=0
begin
set #sqlstring = 'SELECT ''' + #tablename + ''' AS ''TABLE'', [LAST_REFRESHED] FROM ' + #tablename
exec sp_executesql #sqlstring
fetch next from cur into #tablename
end
close cur
deallocate cur
;
It is the weekend and I don't have access to a database to test on, so it may need some adjusting. Here is a fiddle with the sample code, but it only returns the first table http://sqlfiddle.com/#!18/a5b55b/2 (I think the fiddle execution mechanism interferes with the cursor.)
This answer is based upon the code here: I have the same column in multiple tables, and want to update that column in all tables to a specific value. How can I do this?
Note that there is no need to maintain a list of tables with the column. You can generate it dynamically from INFORMATION_SCHEMA.COLUMNS
Another possible approach is to generate and execute a dynamic statement (it's not possible to use a variable for the name of a column or a table):
Table:
CREATE TABLE #TableNames (
[TableName] nvarchar(128)
)
INSERT INTO #TableNames
([TableName])
VALUES
(N'Table1'),
(N'Table2'),
(N'Table3'),
(N'Table4'),
(N'Table5')
Statement:
-- Generate statement
DECLARE #stm nvarchar(max) = N''
SELECT #stm = CONCAT(
#stm,
N'INSERT INTO #DB_DUMMY (TABLENAME, LAST_REFRESHED) ',
N'SELECT ''',
[TableName],
N''' AS [TableName], [LastRefreshed] FROM ',
QUOTENAME([TableName]),
N'; '
)
FROM #TableNames
-- Execute statement
PRINT #stm
EXEC sp_executesql #stm

MSSQL: procedure to remove duplicates

Consider the table which does not have any primary or foreign keys. I would like to write procedure which will remove all the duplicate rows given the table name.
The row should be considered duplicate of other if all of the fields are the same.
Can you suggest me if this is possible. One thing I tried is to group by every field but this approach is not universal.
You could achieve it using Dynamic-SQL
Quick backed solution (great room for improvements):
CREATE TABLE tab1(a INT, b INT);
INSERT INTO tab1(a,b) VALUES (1,1),(1,1),(1,1),(2,3);
GO
Procedure:
CREATE PROCEDURE dbo.remove_duplicates
#tab_name SYSNAME
,#debug BIT = 0
AS
BEGIN
SET NOCOUNT ON;
-- TODO: validation if table does not exist, raise error
-- TODO: Add #schema parameter
-- TODO: Wrap with BEGIN TRY, omit calculated columns, CAST `TEXT/IMAGE/BINARY`....
DECLARE #sql NVARCHAR(MAX) =
'WITH cte AS
(
SELECT *, rn = ROW_NUMBER() OVER(PARTITION BY <cols> ORDER BY (SELECT 1))
FROM <tab_placeholder>
)
DELETE FROM cte
WHERE rn <> 1;';
DECLARE #cols NVARCHAR(MAX) = STUFF((SELECT ',' + column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #tab_name
AND TABLE_SCHEMA = 'dbo'
FOR XML PATH('')), 1, 1, '');
SET #sql = REPLACE(#sql, '<tab_placeholder>', QUOTENAME(#tab_name));
SET #sql = REPLACE(#sql, '<cols>', #cols);
IF #debug = 1 SELECT #sql;
EXEC dbo.sp_executesql #sql;
END
GO
Execution:
EXEC [dbo].[remove_duplicates] #tab_name = 'tab1', #debug = 1;
SELECT * FROM tab1;
LiveDemo
This will remove duplicates from a table. Your partition by must contain the fields that you wish to group by to determine what a duplicate is. In your case, all of them.
IF OBJECT_ID('tempdb..#TABLE') IS NOT NULL DROP TABLE #TABLE
CREATE TABLE #TABLE ( SOMEINT INT,SOMEVALUE VARCHAR(255) )
INSERT INTO #TABLE ( SOMEINT, SOMEVALUE )
VALUES (1,'VALUE1')
,(1,'VALUE2')
,(1,'VALUE2')
,(1,'VALUE3')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE4')
,(1,'VALUE5')
,(1,'VALUE6')
,(1,'VALUE6')
,(1,'VALUE6')
,(1,'VALUE7')
,(1,'VALUE8')
,(1,'VALUE8')
,(1,'VALUE9')
,(1,'VALUE10')
;WITH dedup
AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY SOMEINT,SOMEVALUE ORDER BY SOMEINT ASC) AS SEQUENCE
FROM #TABLE
)
DELETE
FROM dedup
WHERE SEQUENCE > 1
GO
SELECT * FROM #TABLE
There are number of ways
First,
Create a temp table, and copy distinct data to that temp table. Delete or truncate the data from your actual table. And copy the temp table to your actual table. Drop the temp table
SELECT DISTINCT * INTO #table1 from TABLE1
DELETE FROM TABLE1
INSERT INTO TABLE1
SELECT * FROM #table1
DROP TABLE #table1
or
Second,
Add one column to the table, update that column using ROW_NUMBER PARTITION, then remove the rows where COLUMN <> 1 . Drop the newly created column.

Determine all columns from a table and write them separated by commas in a variable

--Dummy table
create table table1 (
column_order varchar (100)
)
insert into table1 values ('column1')
insert into table1 values ('column2')
insert into table1 values ('column3')
insert into table1 values ('column4')
insert into table1 values ('column5')
insert into table1 values ('column6')
--Start of select
declare #rowsCount INT
declare #i INT = 1
declare #column varchar(1000) = ''
set #rowsCount = (select COUNT(*) from table1)
while #i <= #rowsCount
begin
set #column = #column + (select column_order from table1 where rowid(table1) = #i) + ', '
set #i = #i + 1
end
select #column
This code has the function ROWID thats an IQ-Sybase funktion, and im not sure what other DBMS can use it. And above you have a example what i want my select to look like.
My problem is, you cant use the ROWID function with sys.column or any other systables. Has anyone an idea how to get the same select as mine without using the ROWID function.
If you are using IQ, i constructed the code so you can just type f5 and see the select statement, after that just drop the dummy table.
Use list(). It works in both the ASA system and IQ catalogs.
drop table if exists table1
go
create local temporary table table1 (
column_order varchar (100)
) in system --create table in system
insert into table1 values ('column1')
insert into table1 values ('column2')
insert into table1 values ('column3')
insert into table1 values ('column4')
insert into table1 values ('column5')
insert into table1 values ('column6')
declare #columns varchar(100)
select #columns = list(column_order) from table1
select #columns
go
I may be not understand your need, because I can't see why you need rowdid.
Usually, in TSQL, I do as follow:
declare #someVar as nvarchar(max)
set #someVar = (select
'[' + c.name + '],' as 'data()'
from
sys.columns c
join sys.tables t on c.object_id = t.object_id
where
t.name = 'SomeTableName'
for xml path(''))
print Left(#someVar, Len(#someVar) - 1)
Maybe you will need to use a cursor:
-- #MyTableID has to be definded somewhere or replace
DECLARE #columns varchar(32000)
DECLARE my_cursor CURSOR FOR
SELECT syscolumn.column_name FROM syscolumn WHERE syscolumn.table_id = #MyTableID
OPEN my_cursor
FETCH NEXT my_cursor into #column
WHILE ##FETCH_STATUS = 0
BEGIN
-- put your magic here
-- e.g.
-- SET #columns = #columns + column
FETCH NEXT my_cursor_pkey into #column
END
CLOSE my_cursor
DEALLOCATE my_cursor
Not tested yet, but something like that should work.

Conditional clause to DROP Table

I was trying to write a sql procedure to drop table who have a certain pattern in their names.
Something like the below code :
DECLARE #temp TABLE
(
ID bigint IDENTITY(1,1),
tabname sysname NOT NULL
)
INSERT INTO #temp
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%:%'
DECLARE #ProcessedID bigint = 0
DECLARE #tablename sysname
SELECT #ProcessedID = ID, #tablename = tabname FROM #temp WHERE ID > #ProcessedID ORDER BY ID DESC
WHILE(#ProcessedID IS NOT NULL)
BEGIN
DROP TABLE dbo.[#tablename]
SELECT #ProcessedID = ID, #tablename = tabname FROM #temp WHERE ID > #ProcessedID ORDER BY ID DESC
END
But #tablename is not replaced with the right table name. Can any one point me in the right direction.
You need to do it dynamically when you want to use a variable name as an argument, so you need to wrap it in a string and execute that string and then do some small changes to the WHILE condition to fit.
I'd properly do something like this:
DECLARE #temp TABLE
(
ID bigint IDENTITY(1,1),
tabname sysname NOT NULL
):
INSERT INTO #temp
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE '%:%';
DECLARE #tablename VARCHAR(255);
DECLARE #Count INT = ISNULL((SELECT COUNT(*) FROM #temp AS t), 0);
WHILE(#Count > 0)
BEGIN
SELECT #tablename = tabname FROM #temp AS t; --if the order of drop is not significant
EXEC('DROP TABLE dbo.[' + #tablename+ ']');
DELETE FROM #temp WHERE tabname = #tablename;
SET #Count = ISNULL((SELECT COUNT(*) FROM #temp AS t), 0);
END