Creating a dynamic table inside a postgresql loop - postgresql

In the loop, I need to implement an algorithm in which the tables will be joined.
In this case, tabular data is calculated dynamically in a loop.
Something like this:
FOREACH item IN ARRAY array_item LOOP
-- creating a table that depends on the current array element
\\ table_1 (item)
-- creating a table that depends on the next array element
\\ table_2 (item_next)
-- next is the algorithm in which the JOIN is used
\\..SELECT * FROM table_1 JOIN table_2 ...
END LOOP;
There is no such data type as a table in plpgsql.
I tried creating a temporary table inside the loop for table_1 and table_2, but it doesn't help because can't use a previously created temporarary table name.
What ways can such an algorithm be implemented?

Related

Having a postgres function taking an argument and returning a table how to merge many such results into ingle table (SelectMany)?

I want to do something like LINQ SelectMany in Postgres SQL. I have a function with a signature like this:
CREATE or REPLACE FUNCTION get_objects(id_in int) RETURNS TABLE (name varchar, id_out int)
Each call on it returns 200 rows.
I have a select that returns a table of in_IDs. I want to call my function on each row of such a table and merge them into a single one. In other words, join many lists of rows into a single big table. How to do such a thing in Postgres SQL (not inside function loop)?
Use lateral join.
select l.*
from the_table_of_in_ids as t -- or put the query in brackets here
cross join lateral get_objects(t.id) as l;

Difference between a temporary view created by `WITH` and a temporary view created by `CREATE TEMPORARY VIEW`?

In PostgreSQL:
Does WITH clause create a temporary view or a temporary table? (If I am correct a view stores the code of a query, while a table stores the result of a query)
CREATE TEMPORARY VIEW creates a temporary view available only in the current session.
So what is the difference between a temporary view created by WITH and a temporary view created by CREATE TEMPORARY VIEW?
Database System Concepts seems to imply that WITH creates a temporary view instead of a temporary table:
Since the SQL:1999 version, the SQL standard supports a limited form of recursion, using the with recursive clause, where a view (or temporary view) is
expressed in terms of itself. Recursive queries can be used, for example, to express
transitive closure concisely. Recall that the with clause is used to define a temporary view whose definition is available only to the query in which it is defined.
The additional keyword recursive specifies that the view is recursive.
A common table expression (CTE) is only available for a single query.
A temporary view (like a temporary table) is available for all queries in the current session. It is deleted at the end of the session.
They are not really the same as temporary views.
In postgres CTEs (WITH clause) is materialized into table-like
objects. while views behave more like macros
this effect is most visible when one of the columns is a function that has a side-effect or returns different values.
select generate_series(1,3) as n into temp table a;
a simple table with 1,2,3
create temporary view v as select n,random() as r from a;
select * from v as x join v as y on x.n=y.n;
Using the view: note that random column does not match.
The same sort of result can be had by substituting the view expressions.
select x.n,random(),y.n,random()
from a as x join a as y on x.n=y.n;
or
select * from (select n,random() from a ) as x join
(select n,random() from a ) as y on x.n=y.n;
But with CTE:
with c as (select n,random() as r from a)
select * from c as x join c as y on x.n=y.n;
using the CTE note that the random column matches.
yet another way to make the same query is

SELECT FROM multiple tables INTO one internal Table

My db tables:
db_1
db_2
db_3
My internal table:
it_comb
it_comb has a structure with some fields from db_1, db_2, db_3.
All db tables have different structures.
I want to select everything from db_1, db_2, db_3 into the correct fields of it_comb with a where condition.
I would like to do something like this: (This doesn't work)
SELECT * From db_1, db_2, db_3 into CORRESPONDING FIELDS OF TABLE it_comb WHERE db_1-MATNR LIKE db_2-MATNR AND db_1-MATNR LIKE db_3-MATNR.
Obviously, this doesn't work because I can't use ',' like that. How do I write this in ABAP? So that it_comb is filled with data from db_1, db_2 and db_3.
Another problem is that every time I select something into it_comb, my previous data gets overwritten.
Code example would be appreciated for ABAP-Beginner.
You can use inner join -
SELECT * APPENDING CORRESPONDING FIELDS OF TABLE it_comb
FROM db_1 AS a
INNER JOIN db_2 AS b
ON a~matnr = b~matnr
INNER JOIN db_3 AS c
ON a~matnr = c~matnr
WHERE (Your any other condition).
APPENDING won't overwrite the previous record from internal table it_comb.
Warning: Use APPENDING if internal table is TYPE STANDARD otherwise you'll get dump.
Also check the SELECT - JOIN documentaion
One other thing you can do in the newer ABAP versions is
select * from mara inner join mvke on mvke~matnr = mara~matnr into table #data(lt_combined).
loop at lt_combined into data(ls_combined).
write: / ls_combined-mara-matnr, ls_combined-mvke-vkorg.
endloop.
this will define and populate your internal table in one step without the need for a separate "data" statement.
Note that in a join with *, you will get an internal table with substructures based on the table names -- since the structure is implied in the field-list of the select, you can also do something like this for a more efficient database query (so it doesn't need to return all the fields) which also eliminates the substructures:
select mara~matnr, mvke~vkorg from mara inner join mvke on mvke~matnr = mara~matnr into table #data(lt_combined).
loop at lt_combined into data(ls_combined).
write: / ls_combined-matnr, ls_combined-vkorg.
endloop.
Hope this helps!
Without JOIN I executed SELECT statements one by one as follows
data it_comb type TABLE OF vbak.
select * APPENDING CORRESPONDING FIELDS OF TABLE it_comb FROM vbak UP TO 10 ROWS.
select * APPENDING CORRESPONDING FIELDS OF TABLE it_comb FROM vbrk UP TO 10 ROWS.
select * APPENDING CORRESPONDING FIELDS OF TABLE it_comb FROM likp UP TO 10 ROWS.

are INTO, FROM an JOIN the only ways to get a table?

I'm currently writing a script which will allow me to input a file (generally .sql) and it'll generate a list of every table that's used in that file. the process is simple as it opened the input file, checks for a substring and if that substring exists outputs the line to the screen.
the substring that being checked is tsql keywords that is indicative of a selected table such as INTO, FROM and JOIN. not being a T-SQL wizard those 3 keywords are the only ones i know of that are used to select a table in a query.
So my question is, in T-SQL are INTO, FROM an JOIN the only ways to get a table? or are these others?
There're many ways to get a table, here're some of them:
DELETE
FROM
INTO
JOIN
MERGE
OBJECT_ID (N'dbo.mytable', N'U') where U is the object type for table.
TABLE, e.g. ALTER TABLE, TRUNCATE TABLE, DROP TABLE
UPDATE
However, by using your script, you'll not only get real tables, but maybe VIEW and temporary table. Here're 2 examples:
-- Example 1
SELECT *
FROM dbo.myview
-- Example 2
WITH tmptable AS
(
SELECT *
FROM mytable
)
SELECT *
FROM tmptable

New table with all columns as differences between two base tables columns

I am using Postgres 9.1 and have two tables (tab1 and tab2). I wish to create a third table (tab3) where each column is the difference between respective columns in these tables, i.e. tab3.col1 = (tab1.col1 - tab2.col1). However my tables tab1 and tab2 have a large number columns. Is there an efficient way to create table tab3?
If I were to hard code my desired output I would plan to use the code below. However I wish to avoid this as I have over 60 columns to create and want to avoid any hard-coding errors. The columns may not be in the same order across the two tables, however the naming is consistent across tables.
CREATE TABLE tab3 AS
SELECT a.col1_01 - b.col2_01 AS col3_01,
a.col1_02 - b.col2_02 AS col3_02,
...
...
FROM tab1 a FULL JOIN tab2 b USING (permno, datadate);
You can build the whole statement from information in the system catalog (or information schema) and execute it dynamically with a DO command. That's what I would do.
DO
$do$
BEGIN
EXECUTE (
SELECT 'CREATE TABLE tab3 AS
SELECT '
|| string_agg(format('a.%1$I - b.%1$I AS %1$I', attname)
, E'\n , ' ORDER BY attnum)
|| '
FROM tab1 a
FULL JOIN tab2 b USING (permno, datadate)'
FROM pg_attribute
WHERE attrelid = 'tab1'::regclass
AND attnum > 0 -- exclude system columns (neg. attnum)
AND NOT attisdropped -- no dropped (dead) columns
);
END
$do$;
Assuming that tab1 and tab2 are visible in your search_path.
Produces and executes what you requested exactly. Just replace dummy table and column names with your real names.
Read about format() and string_agg() in the manual.
More information in these related answers:
Table name as a PostgreSQL function parameter
Prepend table name to each column in a result set in SQL? (Postgres specifically)