Postgres SQL Statments, getting the right data - sql

I know Postgres has a lot of functions, and I'm not the fittest in SQL anyways, but I need to know if its possible with Postgres to somehow get the data in a table with that statement-
SELECT table_name
FROM information_schema.tables
where table_schema='public'
I'm getting my tables I created which I want.
eg.
table_name
myTable1
myTable2
myTable3
Each of the Tables has different data filled, but every table has a column version and I want to access it.
Joining the tables wouldn't work at least it didn't went out the way I wanted. What I want is this
table_name
Version
myTable1
21
mytABLE2
12
with
Select version from mytable1 order by version desc limit 1
I get the last version but I would like to combine this somehow
I mean I can join the 3 tables but that's not what I want
So my question is it possible to do it? Or do I have to work around.
Because I believe that getting the table names is on a higher layer

In the end you need dynamic SQL for this. One way to do it, is to use a PL/pgSQL function, another way is to use query_to_xml() to run a dynamic query without the use of PL/pgSQL.
with data as (
select query_to_xml(format('select version
from %I.%I
order by version desc limit 1',
t.table_schema, t.table_name),
true, true, '') as result
from information_schema.tables t
where t.table_schema = 'public'
)
select (xpath('/row/version/text()', result))[1]::text::int as version
from data;
The format() function is used to build a SELECT query the way you need it. The query_to_xml() will then return something like:
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<version>21</version>
</row>
The xpath() function is then used to extract the 21 from that XML. As it returns an array of matches, the [1] is used to extract the first match. This is then converted to an integer.
Note that if there is at least one table that does not contain a column named version this query will fail. You can work around that by extending the WHERE clause to:
where table_schema = 'public'
and exists (select *
from information_schema.columns c
where c.table_schema = t.table_schema
and c.table_name = t.table_name
and c.column_name = 'version'

Related

Retrieve schema name from view definition

In Snowflake, I retrieve different views with the following SQL query:
SELECT * FROM "myDatabase"."mySchema"."VIEWS"
That returns a table with these columns notably:
TABLE_ID
TABLE_NAME
TABLE_SCHEMA_ID
TABLE_SCHEMA
TABLE_CATALOG_ID
TABLE_CATALOG
TABLE_OWNER
VIEW_DEFINITION
For each VIEW_DEFINITION column entries, I am trying to extract all the strings <Schema_Name>.<View_Name> (or at least the <Schema_Name>).
Is it possible to do that with a SQL query (or by any other way)?
Edit
The table I obtain using the initial query is as follows:
TABLE_ID
TABLE_NAME
TABLE_SCHEMA_ID
TABLE_SCHEMA
TABLE_CATALOG_ID
TABLE_CATALOG
TABLE_OWNER
VIEW_DEFINITION
0001
MY_TABLE_NAME
99
MY_TABLE_SCHEMA
20
PMY_TABLE_CATALOG
MY_OWNER_VIEWS_ADMIN
…
where the VIEW_DEFINITION column contains queries like the one below:
"CREATE OR REPLACE VIEW My_Table_Schema_VIEWS.My_Table_Name AS
WITH STUDY_SITE_SCOPE AS (
SELECT
...
FROM (
SELECT
A.SUBJECT_NUMBER
, A.SUBJECT_STATUS
FROM <Schema_Name>.<View_Name_1> X
JOIN <Schema_Name>.<View_Name_2> Y
...
)
JOIN (
SELECT
...
FROM <Schema_Name>.<View_Name_3> X
JOIN <Schema_Name>.<View_Name_4> Y
...
)
..."
From this VIEW_DEFINITION I am trying to extract all the <Schema_Name>.<View_Name_XX> strings (or at least the <Schema_Name>).
I assume you want to get all base schemas your current view is built on top of.
To answer your question short: Yes, it is.
Maybe the following procedure is giving you an idea on how to solve it via SQL or a Stored Procedure:
Query the view definition
Search for all strings within the view definition that follow the "FROM" or "JOIN" clause
Extract them and probably check for the database name in front of the schema name
You can use information_schema.tables:
select t.*
from information_schema.tables t
where t.table_type = 'VIEW'

SQL inner join based on table name pattern

On this legacy SQL Database with hundreds of tables, I need to do a inner join on all tables whose name follows a format:
barX_foo_bazX
barX_foo_bazY
barZ_foo_bazZ
I would like to inner join all tables with foo in their name
I am not sure this is possible at all.
Clearly, with this syntax it is not (but it may help understand what I'm aiming at):
USE [LegacyDB_Name]
SELECT *
FROM '%_foo_%' inner join '%_foo_%'
where my_stuff_is(some condition)
Any Suggestions? Ideas on how I can do this? Maybe there is an easier path this young padawan is not seeing...
Many Thanks!
I am not sure this is possible at all.
Nope, table names cannot contain or use wildcards, they must be strings.
My advice would be to find whatever program makes these select queries and include whatever pattern matching you need in the queries in there.
But your finished query must contain table names as strings.
Maybe the simplest way to do this is to declare a cursor based on the below query and build a dynamic sql query. Research tsql cursor and dynamic sql execution and it should be fairly simple.
SELECT *
FROM information_schema.tables
Where Table_Type = 'Base Table' And Table_Name Like '%_foo_%'
If your tables all have the same structure (i.e. columns), then you could do this in two steps.
Generate the SQL statement:
select 'UNION ALL SELECT ''' + table_name + ''' AS table_name, * FROM '
+ table_name AS stmt
from information_schema.tables
where table_type = 'BASE TABLE'
and table_catalog = 'LegacyDB_Name'
and table_name LIKE '%foo%';
The output will be something like:
stmt
--------------------------------------------------------------------
UNION ALL SELECT 'barX_foo_bazX' AS table_name, * FROM barX_foo_bazX
UNION ALL SELECT 'barX_foo_bazY' AS table_name, * FROM barX_foo_bazY
UNION ALL SELECT 'barX_foo_bazZ' AS table_name, * FROM barX_foo_bazZ
From this output, copy the SQL rows and remove the first 2 words (UNION ALL) from the first line. This is a valid SQL statement.
Execute the SQL statement derived above
If you need this SQL more often, then create a view for it:
CREATE OR REPLACE VIEW all_foo AS
SELECT 'barX_foo_bazX' AS table_name, * FROM barX_foo_bazX
UNION ALL SELECT 'barX_foo_bazY' AS table_name, * FROM barX_foo_bazY
UNION ALL SELECT 'barX_foo_bazZ' AS table_name, * FROM barX_foo_bazZ;
Now you can query like
SELECT * FROM all_foo WHERE ...

Vertica Dynamic Max Timestamp from all Tables in a Schema

System is HP VERTICA 7.1
I am trying to create a SQL query which will dynamically find all particular tables in a specific schema that have a Timestamp column named DWH_CREATE_TIMESTAMP from system tables. (I have completed this part successfully)
Then, pass this list of tables to an outer query or some kind of looping statement which will select the MAX(DWH_CREATE_TIMESTAMP) and TABLE_NAME from all the tables in the list (200+) and union all the results together into one list.
The expected output is a 2 column table with all said tables with that TS field and the max of each value. Tables are constantly being created and dropped, so the point is to make everything totally dynamic where no TABLE_NAME values are ever hard-coded.
Any idea of Vertica specific ways to accomplish this without UDF's would be greatly appreciated.
Inner Query (working):
select distinct(table_name)
from columns
where column_name = 'DWH_CREATE_TIMESTAMP'
and table_name in (select DISTINCT(table_name) from all_tables where schema_name = 'PTG_DWH')
Outer Query (attempted - not working):
SELECT Max(DWH_CREATE_DATE) from
WITH table_name AS (
select distinct(table_name)
from columns
where column_name = 'DWH_CREATE_DATE' and table_name in (select DISTINCT(table_name) from all_tables where schema_name = 'PTG_DWH'))
SELECT MAX(DWH_CREATE_DATE)
FROM table_name
Thanks!!!
No way to do that in one SQL .
You can used the below method for node max timestamp columns values
select projections.anchor_table_name,vs_ros.colname,max(max_value) from vs_ros,vs_ros_min_max_values,storage_containers,projections where vs_ros.colname ilike 'timestamp'
and vs_ros.salstorageid=storage_containers.sal_storage_id
and vs_ros_min_max_values.rosid=vs_ros.rosid
and storage_containers.projection_name=projections.projection_name
group by projections.anchor_table_name,vs_ros.colname

one query for many similar tables

I have an Oracle database with many tables that have identical structure (columns are all the same). The table names are similar also. The names of the tables are like table_1, table_2, table_3...
I know this isn't the most efficient design, but I don't have the option of changing this at this time.
In this case, is it possible to make a single sql query, to extract all rows with the same condition across multiple tables (hundreds of tables) without explicitly using the exact table name?
I realize I could use something like
select * from table_1 UNION select * from table_2 UNION select * from table_3...select * from table_1000
But is there a more elegant sql statement that can be run that extracts from all matching table names into one result without having to name each table explicitly.
Something like
select * from table_%
Is something like that possible? If not, what is the most efficient way to write this query?
You can use dbms_xmlgen to query tables using a pattern, which generates an XML document as a CLOB:
select dbms_xmlgen.getxml('select * from ' || table_name
|| ' where some_col like ''%Test%''') as xml_clob
from user_tables
where table_name like 'TABLE_%';
You said you wanted a condition, so I've included a dummy one, where some_col like '%Test%'.
You can then use XMLTable to extract the values back as relational data, converting the CLOB to XMLType on the way:
select x.*
from (
select xmltype(dbms_xmlgen.getxml('select * from ' || table_name
|| ' where some_col like ''%Test%''')) as xml
from user_tables
where table_name like 'TABLE_%'
) t
cross join xmltable('/ROWSET/ROW'
passing t.xml
columns id number path 'ID',
some_col varchar2(10) path 'SOME_COL'
) x;
SQL Fiddle demo which retrieves one matching row from each of two similar tables. Of course, this assumes your table names follow a useful pattern like table_%, but you suggest they do.
This is the only way I know to do something like this without resorting to PL/SQL (and having searched back a bit, was probably inspired by this answer to count multiple tables). Whether it's efficient (enough) is something you'd need to test with your data.
This is kind of messy and best performed in a middle-tier, but I suppose you could basically loop over the tables and use EXECUTE IMMEDIATE to do it.
Something like:
for t in (select table_name from all_tables where table_name like 'table_%') loop
execute immediate 'select blah from ' || t.table_name;
end loop;
You can write "select * from table_1 and table_2 and tabl_3;"

sum of all columns in sql

sum of all columns in sql
i have 48 columns with 40,000 rows.
I want a new row which is sum of all columns.
I know I can do:
select sum(a), sum(b), sum(c) .....but i have to type that 48 times.
Is there a better way ?
the column has int values. And also has a lot of 0's
This problem smacks of poor design, you should fix your structure, most likely each of your 48 column names could be a value in a single column next to the column you're aggregating (or another table altogether).
Then you'd have a simple query like below that returns 48 rows:
SELECT col1,SUM(col2)
FROM YourTable
GROUP BY col1
Fixing the structure is ideal, but you can get what you're after using system views:
SELECT ',SUM('+c.name+')'
FROM sys.tables t
JOIN sys.columns c
ON t.object_id = c.object_id
WHERE t.name = 'YourTable'
You could make it dynamic so you can execute it all at once, but if you're just looking for a quick way to save some keystrokes that will work.
Actually, you are not forced to use sum 48 times.
You can retrieve all the column names querying the information_schema. Then loop over all these columns and execute the query.
This query would return the column_names of your table :
select column_name
from information_schema.columns
where table_name = 'yourTable'
and table_schema = 'yourSchema'
Then you just need to loop over each column_name and execute the query as a string using sp_executesql. Simply set the column name in the string the value of the current iteration in the loop.
If you want all the columns returned in one time, you can use union.
I think you have all what is needed here to accomplish what you want.