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
Related
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
Is the script structure below possible?
Select
*,
(Select Count(*)
from [A.DatabaseName].dbo.TableA
where SomeID = A.SomeID) As Total
From
[Database1].dbo.Table1 A
The subquery above is dependent on the database name from [Database1].
Is this doable? If yes, how can this be implemented?
The Dynamic Query will help you.
DECLARE #DBName VARCHAR(100),#SQLQuery VARCHAR(1000)
SELECT #DBName = A.DatabaseName FROM [Database1].dbo.Table1
SELECT #SQLQuery = 'Select
*,
(Select Count(*)
from '+#DBName+'.dbo.TableA
where SomeID = A.SomeID) As Total
From
[Database1].dbo.Table1 A'
EXEC (#SQLQuery)
---> Edit
I think i understand the weird thing you are tying to do.
You store some database name into a table and the want to call if from a subquery.
You have to try something like this :
CREATE DATABASE test
use test
CREATE TABLE client
(
ID IDENTITY(1,1),
[name] varchar(20)
)
INSERT INTO client
([name])
VALUES
('Jean'), ('Paul'), ('Mark'), ('Pierre');
CREATE TABLE allTable
(
NomSchema VARCHAR(200),
NomTable VARCHAR(200)
)
INSERT INTO allTable
VALUES
(
'TEST','client'
)
IF OBJECT_ID('tempdb..#ResultA') IS NOT NULL
DROP TABLE #ResultA
BEGIN TRAN
DECLARE #sql VARCHAR(200);
SELECT TOP(1) * INTO #resultA FROM allTable
SET #sql = 'SELECT * FROM ' + (SELECT quotename(#resultA.NomSchema) + '.dbo.' + quotename(#resultA.NomTable) FROM #resultA)
SELECT #sql
EXEC(#sql)
DROP TABLE #resultA
COMMIT
GO
-- DROP DATABASE TEST
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
I have two tables, Values and SpecialValues.
Values has two columns, RecordID and ValueName.
SpecialValues is a table which contains a single row, and thirty columns named SpecialValueName1, SpecialValueName2, SpecialValueName3, etc.
There are obvious database design problems with this system.
That aside, can someone explain to me how to query SpecialValues so that I can get a collection of all the values of every row from the table, and exclude them from a Select from Values?
There's probably some easy way to do this or create a View for it or something, but I think looking at this code might have broken me for the moment...
EDIT: I'd like a query to get all the individual values from every row and column of a given table (in this case the SpecialValues table) so that the query does not need to be updated the next time someone adds another column to the SpecialValues table.
This creates a #SpecialValuesColumns temporary table to store all the column names from SpecialValues.
It then uses a cursor to insert all the values from each of those columns into another temporary table #ProtectedValues.
It then uses a NOT IN query to exclude all of those values from a query to Values.
This code is bad and I feel bad for writing it, but it seems like the least-worst option open to me right now.
DECLARE #SpecialColumnsCount INT;
DECLARE #Counter INT;
DECLARE #CurrentColumnName VARCHAR(255);
DECLARE #ExecSQL VARCHAR(1024);
SET #Counter = 1;
CREATE TABLE #ProtectedValues(RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, Value VARCHAR(255));
DECLARE #SpecialValuesColumns TABLE (RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, ColumnName VARCHAR(255));
INSERT INTO #SpecialValuesColumns (ColumnName)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'SpecialValues' AND
DATA_TYPE = 'varchar' AND
CHARACTER_MAXIMUM_LENGTH = 255
SELECT #SpecialColumnsCount = COUNT(*) FROM #SpecialValuesColumns
WHILE #Counter <= #SpecialColumnsCount
BEGIN
SELECT #CurrentColumnName = ColumnName FROM #SpecialValuesColumns WHERE RecordID = #Counter;
SET #ExecSQL = 'INSERT INTO #ProtectedValues (Value) SELECT ' + #CurrentColumnName + ' FROM SpecialValues'
EXEC (#ExecSQL)
SET #Counter = #Counter + 1;
END
SELECT * FROM Values WHERE ValueName NOT IN (SELECT ValueName COLLATE DATABASE_DEFAULT FROM #ProtectedValues)
DROP TABLE #ProtectedValues;
I might have misunderstood but doesn't this do it?
SELECT * FROM Values
WHERE ValueName NOT IN (
SELECT SpecialValueName1 FROM SpecialValues
UNION SELECT SpecialValueName2 FROM SpecialValues
UNION SELECT SpecialValueName3 FROM SpecialValues
etc..
)
You could of course make the subquery into a view instead.
*Edit:
This is quite ugly but should solve your problem:
First Create procedure #1
CREATE PROCEDURE [dbo].[SP1]
As
DECLARE
#Query nvarchar(MAX),
#Table nvarchar(255),
#Columns nvarchar(255)
CREATE TABLE #TempTable (Value nvarchar(255))
SET #Table = 'SpecialValues'
SELECT [COLUMN_NAME]
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = #Table
DECLARE Table_Cursor CURSOR FOR
SELECT COLUMN_NAME
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = #Table
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO #Columns
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #TempTable EXEC SP2 #Columns = #Columns, #Table = #Table
FETCH NEXT FROM Table_Cursor INTO #Columns
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor
SELECT ValueName FROM Value WHERE Value NOT IN (SELECT * FROM #TempTable)
TRUNCATE TABLE #TempTable
DROP TABLE #TempTable
Then Create procedure #2
CREATE PROCEDURE [dbo].[SP2]
#Columns nvarchar(255) = '',
#Table nvarchar(255)
AS
DECLARE
#Query nvarchar(MAX)
SET #Query = 'SELECT TOP 1 CONVERT(nvarchar, ' + #Columns + ') FROM ' + #Table
EXEC (#Query)
Then lastly execute the procedure
EXEC SP1
You need to unpivot the values in specialvalues. A pretty easy way to do that is with cross apply syntax:
select sv.value
from specialvalues sv cross apply
(values(sv.SpecialValueName1), (sv.SpecialValueName2), . . .
) sv(value)
where sv.value is not null;
You can exclude these from the list using not in, not exists or a left join.
What ever way you cut it, you have to specify the columns in SpecialValues, you can do this with a long set of UNION queries, or use UNPIVOT:
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
You can then incorporate this into a query on Values using NOT IN
select * from [Values] where ValueName not in (
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
)
My query returns 26 table names.
select name from sys.tables where name like '%JPro_VP_Service%'
Now I'm trying to write a query to check in every table return from the above query.
--consider this is my first table
select * from JPro_VP_Service
where row_id like '%1-101%' or row_id like '%1-102%'
-- likewise I want to search in 26 tables return from above query
I think I need to write for or cursor to accomplish this.
Can anyone help me how to achieve this?
The easiest way to do this is
Try this:
SELECT 'select * from ' + name
+ ' where row_id like ''%1-101%'' or row_id like ''%1-102%'''
FROM sys.tables
WHERE name LIKE '%JPro_VP_Service%'
you will get all tables together with the same conditions. You could execute them together.
Yes, you would have to use a cursor for this, and probably also dynamic sql
Also see
Generate dynamic SQL statements in SQL Server
Dynamic SQL PROs & CONs
DECLARE #mn INT
DECLARE #mx INT
DECLARE #tblname VARCHAR(100);
WITH cte
AS (SELECT Row_number()
OVER (
ORDER BY (SELECT 0)) AS rn,
name
FROM sys.tables
WHERE name LIKE '%JPro_VP_Service%')
SELECT #mn = Min(rn),
#mx = Max(rn)
FROM cte
WHILE( #mn >= #mx )
BEGIN
SELECT #tblname = name
FROM cte
WHERE rn = #mn
SELECT *
FROM #tblname
WHERE row_id LIKE '%1-101%'
OR row_id LIKE '%1-102%'
--Do something else
SET #mn=#mn + 1
END
This route may work, though you might want the results saved to a table:
DECLARE #tables TABLE(
ID INT IDENTITY(1,1),
Name VARCHAR(100)
)
INSERT INTO #tables (Name)
SELECT name
FROM sys.tables
WHERE name like '%JPro_VP_Service%'
DECLARE #b INT = 1, #m INT, #table VARCHAR(100), #cmd NVARCHAR(MAX)
SELECT #m = MAX(ID) FROM #tables
WHILE #b <= #m
BEGIN
SELECT #table = Name FROM #tables WHERE ID = #b
SET #cmd = 'select * from ' + #table + '
where row_id like ''%1-101%'' or row_id like ''%1-102%''
'
EXECUTE sp_executesql #cmd
SET #b = #b + 1
SET #cmd = ''
END