The ask is to get the definition of all the views from Production environment and refresh the lower environment. I assume, GET_DDL in a loop will suffice the need but not sure how to implement it. Please advise.
Assuming that VIEW_DEFITION is not enough:
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, VIEW_DEFINITION
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA != 'INFORMATION_SCHEMA';
and GET_DDL is required:
DECLARE
CUR CURSOR FOR SELECT CONCAT_WS('.',TABLE_CATALOG,TABLE_SCHEMA,TABLE_NAME) AS name
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA NOT IN ('INFORMATION_SCHEMA');
BEGIN
CREATE OR REPLACE TEMPORARY TABLE temp_view_defs(view_name TEXT, definition TEXT);
FOR rec IN CUR DO
EXECUTE IMMEDIATE REPLACE('INSERT INTO temp_view_defs(view_name, definition)
SELECT ''<view_name>'', GET_DDL(''TABLE'', ''<view_name>'')'
,'<view_name>'
,rec.name);
END FOR;
LET rs RESULTSET := (SELECT * FROM temp_view_defs);
RETURN TABLE(rs);
END;
Sample output:
Check this. You can download the results and use it to get the DDL of all views, at once.
SELECT 'SELECT GET_DDL(''VIEW'',''' || table_name || ''');' AS stmt
FROM INFORMATION_SCHEMA.views
WHERE table_name NOT IN('TABLES','COLUMNS','SCHEMATA','SEQUENCES','VIEWS','TABLE_PRIVILEGES','USAGE_PRIVILEGES','DATABASES','REPLICATION_DATABASES','REPLICATION_GROUPS','FUNCTIONS','PROCEDURES','OBJECT_PRIVILEGES','OBJECT_PRIVILEGES','FILE_FORMATS','APPLICABLE_ROLES','ENABLED_ROLES','STAGES','REFERENTIAL_CONSTRAINTS','TABLE_CONSTRAINTS','INFORMATION_SCHEMA_CATALOG_NAME','LOAD_HISTORY','TABLE_STORAGE_METRICS','PIPES','EXTERNAL_TABLES','LOGGERS','EVENT_TABLES','PACKAGES');
Thanks all for suggesting your solutions. I found below code is much more close to my requirement; copy entire VIEWS in one go:
select view_definition from information_schema.views
where table_schema = 'XYZ'
Copy the the view_definition > Execute it.
Related
I am trying to use an array to pull table information. My array build seems to be fine and it is created with the correct number of rows.
THis is what I have so far:
DECLARE #myTableVariable TABLE (name varchar(30))
insert into #myTableVariable SELECT [NAME] FROM SYS.DATABASES
SELECT
TABLE_CATALOG AS 'DATABASE',
TABLE_NAME,
COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH
FROM #myTableVariable.information_schema.columns
I hope my question makes sense! Thanks in advance!
I know there needs to be some sort of WHILE loop around the SQL statement portion, but I am unsure how to properly form it. I have been looking around with no luck.
You can achieve what you're trying to do with a little bit of Dynamic SQL.
In SQL Server I would prefer to use the system DMVs instead of Information_Schema (which really only exist for compatability) however, assuming you have permission to access the database(s) and don't have conflicting collations, the following should help:
declare #Sql nvarchar(max);
with db as (select name from master.sys.databases where database_id > 4)
select #Sql = string_agg(Convert(nvarchar(max), Concat(N'
select
TABLE_CATALOG as [DATABASE],
TABLE_NAME,
COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH
from ', QuoteName(db.name), N'.information_schema.columns')), N' union all ')
from db;
select #Sql;
exec (#Sql);
A customer's 96GB SQL Server 2014 accounting database has about 1,000 tables, none of which has constraints or fkeys applied or is otherwise documented. I have read only access, with basically other no rights.
A user has sent me a screenshot showing a value that is stored somewhere in the database. The value is "51210000", which might also be stored as a pointer to its entry in the ACCOUNTS table, 323.
I have seen various solutions to searching an entire db, but they invariably use temporary tables, procedures, or other solutions that require write access. Can anyone offer a way to do this read-only?
It's going to be a bit slow, but you can run these a few at a time to see where it may exist
SELECT CONCAT('select * from ', TABLE_NAME, ' where ', COLUMN_NAME, ' = ''51210000''')
FROM INFORMATION_SCHEMA.COLUMNS
Perhaps sp_MSforeachtable
This is certainly NOT fast and I would suggest testing on a smaller database.
Example
Declare #Results table (TableName varchar(500),RowData varchar(max))
Insert Into #Results
EXEC sp_MSforeachtable 'SELECT TableName=''?'' ,RowData = (Select A.* for XML Raw) FROM ? A Where (Select A.* for XML Raw) like ''%51210000%'''
Select *
From #Results
Note:
If 2016+, you may get a little boost by using the JSON alternative.
Replace (Select A.* for XML Raw)
With (Select A.* for JSON Path)
Just for fun
I ran a test looking for "Consulting" on a 17GB database (214 tables). It took 1 minute 30 seconds to return
EDIT - Dynamic SQL Approach
Declare #SQL varchar(max)
Set #SQL=Stuff((Select 'Union All ' +Expr
From (
Select Expr = 'Select Table_Schema='''+Table_Schema+''',Table_Name='''+Table_Name+''',Column_Name='''+Column_Name+''',Value=cast('+quotename(Column_Name)+' as varchar(max)) From '+quotename(Table_Schema)+'.'+quoteName(Table_Name)+' Where '+quotename(Column_Name)+' like ''%Cappe%''||'
From INFORMATION_SCHEMA.COLUMNS
Where Data_Type in ('varchar','int','float','bigint') -- << Set Your Desired Filter
and Table_Name not like 'vw_%' -- << I'd tend to exclude views my prefix vw_
) A
For XML Path ('')),1,10,'')
Set #SQL = replace(#SQL,'||',char(13))
Print #SQL
Exec(#SQL)
Returns
I am trying to write a simple SQL query in pgAdmin to LOOP through each table in a database and change a specified column name IF it exists. I have never coded in SQL but after searching through many forums have managed to come up with:
DO
BEGIN
FOR i IN SELECT table_name FROM information_schema.tables
LOOP
IF SELECT column_name FROM information_schema.columns WHERE table_name = 'i.table_name'
THEN
ALTER TABLE i.table_name RENAME COLUMN old_column_name TO new_column_name
END IF;
END LOOP;
You can skip information_schema.tables entirely. Just:
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
SELECT table_schema, table_name, column_name
FROM information_schema.columns
WHERE column_name = 'x'
LOOP
EXECUTE format('ALTER TABLE %I.%I RENAME COLUMN %I TO newname;',
rec.table_schema, rec.table_name, rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
with appropriate substitutions for 'x' and newname. Or make it into a function that takes them as parameters, whatever.
It doesn't seem like you need to query tables, just query columns for the old column name, and get the table it's in.
You will need to use Dynamic SQL to do the renames.
See here on how to loop through query results. This of course needs to be done in a PL/pgSQL function.
The correct answer for your question was posted above. Alternately if you are trying to simply drop a column from all your tables as I was trying to do, then you can do it this way
DO
$$
DECLARE
rec record;
BEGIN
FOR rec IN
SELECT table_schema, table_name, column_name
FROM information_schema.columns
WHERE column_name = 'my_column_name_to_drop'
LOOP
EXECUTE format('ALTER TABLE %I.%I DROP %I;',
rec.table_schema, rec.table_name, rec.column_name);
END LOOP;
END;
$$
LANGUAGE plpgsql;
Where my_column_name_to_drop is the actual column you are searching for.
is there a way to simply select the result returned from sp_tables?
No there isn't.
But you could try to replace sp_tables by querying the information_schema.
For example:
sp_tables 'T_Raum'
You can substitute with this:
SELECT
TABLE_CATALOG AS TABLE_QUALIFIER,
TABLE_SCHEMA AS TABLE_OWNER,
TABLE_NAME,
CASE TABLE_TYPE
WHEN 'BASE TABLE' THEN 'TABLE'
ELSE TABLE_TYPE
END AS TABLE_TYPE,
NULL AS REMARKS
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE != 'VIEW'
AND TABLE_NAME = 'T_Raum'
I don't know what exactly sp_tables does, or what you need it for, but at least in this case, it seems to do the above schema query.
If you call sp_tables, the result you get is the result of a SELECT statement.
In that respect, it is no different than any store procedure that returns a result set.
If you mean you want to filter the resultset returned by that sproc then depending on what you want to filter on, you can pass in params to that sproc (e.g. #table_name parameter, which supports wildcards). Check out the BOL ref on sp_tables
Alternatively, you will need to insert the results into a temp table and select from that.
Or finally, depending on what you want, you could query the sys tables directly. If only interested in tables:
SELECT *
FROM sys.tables
WHERE...
If you want to select from each table, you can use the undocumented sp_msforeachtable command:
sp_msforeachtable 'SELECT * FROM ?'
The ? is a wildcard that indicates the current table name, and the command needs to be a string enclosed in single quotes just like in other Dynamic SQL.
We have a problem with our table schema falling out of sync with our view schema. I would like to know how I could have a stored procedure (for Sql Server) that gets all views in the database, and executes each one via select *
Here is what I imagined (pseudo):
Declare x
Set x = Select object from sysobjects where object = view
foreach view in x
sp_execute 'select * from view'
We could then have an automated test that calls this every night. A SqlException would indicated that something was out of sync.
should work in 2000 and up
select quotename(table_schema) +'.' + quotename(table_name) as ViewNAme,
identity(int,1,1) as ID
into #test
from information_schema.tables
where table_type = 'view'
declare #Loopid int,#MaxID int
select #LoopID =1,#MaxID =MAX(id)
from #test
declare #ViewName varchar(100)
while #LoopID <= #MaxID
begin
select #ViewName = ViewNAme
from #test
where id = #LoopID
exec ('select top 1 * from ' + #ViewName)
set #LoopID = #LoopID + 1
end
drop table #test
I mostly focused on one part of your question, see also how to make sure that the view will have the underlying table changes by using sp_refreshview
I'd really suggest you use WITH SCHEMABINDING to prevent this happening.
Or use sp_refreshview in a loop at least.
SELECT * FROM view is not reliable: how do know if the output is correct or not?
In SQL 2008 you can use the following to detect unresolved dependencies without having to actually select from the view.
SELECT *
FROM sys.views v
JOIN sys.sql_expression_dependencies e ON e.referencing_id = v.object_id
and referenced_id is null