copy data from 2 separate tables in postgresql - sql

Just wondering is it possible to extract data from 2 different tables at one time in postgresql
I have the following:
Blocks Table - has been created as follows in order to fit a schema, so the JSON information has all been stored in an information column containing 36 polygons each
UUID (UUID)
Name (TEXT)
Type (TEXT)
Information (TEXT)
815b2ce7-ce99-4d6c-b41a-bec512173f53
C2
Block
'stored JSON info'
7a9a03fc-8be6-47ca-b743-43715ebb5610
D2
Block
'stored JSON info'
9136dcda-2a55-4084-87c1-68ccde23aed8
E3
Block
'stored JSON info'
For a later query, I need to know the geometries of each of the polygons, so I created another table using a code which parsed them out:
CREATE TABLE blockc2_ AS SELECT geom FROM (SELECT elem->>'type' AS type, elem->'properties' AS prop, elem->'geometry' AS geom FROM (SELECT json_array_elements(data) elem FROM block) f1)f2;
A final table is created to show just the geometries (which will a associated with the already created UID's like below
new_table
UUID (UUID)
Geometry (Geometry)
815b2ce7-ce99-4d6c-b41a-bec512173f53
01030000000100000005000000972E05A56D6851C084D91C434C6C32401C05D4886B6851C086D974FA4D6C324078F4DA916D6851C036BF7504766C3240F31D0CAE6F6851C035BF1D4D746C3240972E05A56D6851C084D91C434C6C3240
7a9a03fc-8be6-47ca-b743-43715ebb5610
01030000000100000005000000BB05694F726851C0CB2A87A8486C32403EDC3733706851C0CD2ADF5F4A6C32409ACB3E3C726851C07E10E069726C324017F56F58746851C07C1088B2706C3240BB05694F726851C0CB2A87A8486C3240
9136dcda-2a55-4084-87c1-68ccde23aed8
1030000000100000005000000972E05A56D6851C084D91C434C6C32401C05D4886B6851C086D974FA4D6C324078F4DA916D6851C036BF7504766C3240F31D0CAE6F6851C035BF1D4D746C3240972E05A56D6851C084D91C434C6C3240
Ideally, I need a code like below (if its possible) because if I insert them separately they don't associate with each other. Instead of 3 rows of info, it will be 6 (3 UUIDS and 3 Geometries)
INSERT INTO new_table (uuid, geometry) SELECT UUID FROM blocks WHERE Name='C2' AND SELECT geometry FROM second_table WHERE Name='C2'
Is something like this possible?

create table C (select * from table B union all select * from table A)

This sounds like a join:
INSERT INTO new_table (uuid, geometry)
SELECT b.UUID, g.geometry
FROM blocks b JOIN
geometry g
USING (name)
WHERE Name = 'C2';

Related

Search using LIKE operator with multiple dynamic values accepting both full and partial text match

Is there any way to do multiple term search in a column using like operator dynamically in SQL Server? Like below
SELECT ID
FROM table
WHERE
Company LIKE '%goog%' OR
Company LIKE '%micros%' OR
Company LIKE '%amazon%'
For example: input values "goog; micro; amazon;" (input value should auto split by delimiter ';' and check the text exist in the table) means that Search term 'goog' or 'micros' or 'amazon' from company column, if exists return.
Table - sample data:
ID Company
------------------------------------------
1 Google; Microsoft;
2 oracle; microsoft; apple; walmart; tesla
3 amazon; apple;
4 google;
5 tesla;
6 amazon;
Basically, The above query should return the results as like below,
Desired results:
ID
-----
1
2
4
6
Is it possible to achieve in SQL Server by splitting, then search in query? I look forward to an experts answer.
If you pass in a table valued parameter, you can join on that.
So for example
CREATE TYPE StringList AS TABLE (str varchar(100));
DECLARE #tmp StringList;
INSERT #tmp (str)
VALUES
('%goog%'),
('%micros%'),
('%amazon%');
SELECT t.ID
FROM table t
WHERE EXISTS (SELECT 1
FROM #tmp tmp
WHERE t.Company LIKE tmp.str);
The one issue with this is that someone could write le; Mic and still get a result.
Strictly speaking, your table design is flawed, because you are storing multiple different items in the same column. You really should have this normalized into rows, so every Company is a separate row. Then your code would look like this:
SELECT t.ID
FROM table t
JOIN #tmp tmp ON t.Company LIKE tmp.str
GROUP BY t.ID
You can simulate it by splitting your string
SELECT t.ID
FROM table t
WHERE EXISTS (SELECT 1
FROM STRING_SPLIT(t.Company) s
JOIN #tmp tmp ON s.value LIKE tmp.str);

How to delete records in BigQuery based on values in an array?

In Google BigQuery, I would like to delete a subset of records, based on the value of a specific column. It's a query that I need to run repeatedly and that I would like to run automatically.
The problem is that this specific column is of the form STRUCT<column_1 ARRAY (STRING), column_2 ARRAY (STRING), ... >, and I don't know how to use such a column in the where-clause when using the delete-command.
Here is basically what I am trying to do (this code does not work):
DELETE
FROM dataset.table t
LEFT JOIN UNNEST(t.category.column_1) AS type
WHERE t.partition_date = '2020-07-22'
AND type = 'some_value'
The error that I'm getting is: Syntax error: Expected end of input but got keyword LEFT at [3:1]
If I replace the DELETE with SELECT *, it does work:
SELECT *
FROM dataset.table t
LEFT JOIN UNNEST(t.category.column_1) AS type
WHERE t.partition_date = '2020-07-22'
AND type = 'some_value'
Does somebody know how to use such a column to delete a subset of records?
EDIT:
Here is some code to create a reproducible example with some silly data (fill in your own dataset and table name in all queries):
Suppose you want to delete all rows where category.type contains the value 'food'.
1 - create a table:
CREATE TABLE <DATASET>.<TABLE_NAME>
(
article STRING,
category STRUCT<
color STRING,
type ARRAY<STRING>
>
);
2 - Insert data into the new table:
INSERT <DATASET>.<TABLE_NAME>
SELECT "apple" AS article, STRUCT('red' AS color, ['fruit','food'] as type) AS category
UNION ALL
SELECT "cabbage" AS article, STRUCT('blue' AS color, ['vegetable', 'food'] as type) AS category
UNION ALL
SELECT "book" AS article, STRUCT('red' AS color, ['object'] as type) AS category
UNION ALL
SELECT "dog" AS article, STRUCT('green' AS color, ['animal', 'pet'] as type) AS category;
3 - Show that select works (return all rows where category.type contains the value 'food'; these are the rows I want to delete):
SELECT *
FROM <DATASET>.<TABLE_NAME>
LEFT JOIN UNNEST(category.type) type
WHERE type = 'food'
Initial Result
4 - My attempt at deleting rows where category.type contains 'food' does not work:
DELETE
FROM <DATASET>.<TABLE_NAME>
LEFT JOIN UNNEST(category.type) type
WHERE type = 'food'
Syntax error: Unexpected keyword LEFT at [3:1]
Desired Result
This is the code I used to delete the desired records (the records where category.type contains the value 'food'.)
DELETE
FROM <DATASET>.<TABLE_NAME> t1
WHERE EXISTS(SELECT 1 FROM UNNEST(t1.category.type) t2 WHERE t2 = 'food')
The embarrasing thing is that I've seen these kind of answers on similar questions (for example on update-queries). But I come from Oracle-SQL and I think that there you are required to connect your subquery with your main query in the WHERE-statement of the subquery (ie. connect t1 with t2), so I didn't understand these answers. That's why I posted this question.
However, I learned that BigQuery automatically understands how to connect table t1 and 'table' t2; you don't have to explicitly connect them.
Now it is possible to still do this (perhaps even recommended?):
DELETE
FROM <DATASET>.<TABLE_NAME> t1
WHERE EXISTS (SELECT 1 FROM <DATASET>.<TABLE_NAME> t2 LEFT JOIN UNNEST(t2.category.type) AS type WHERE type = 'food' AND t1.article=t2.article)
but a second difficulty for me was that my ID in my actual data is somehow hidden in an array>struct-construction, so I got stuck connecting t1 & t2. Fortunately this is not always an absolute necessity.
Since you did not provide any sample data I am going to explain using some dummy data. In case you add your sample data, I can update the answer.
Firstly,according to your description, you have only a STRUCT not an Array[Struct <col_1, col_2>].For this reason, you do not need to use UNNEST to access the values within the data. Below is an example how to access particular data within a STRUCT.
WITH data AS (
SELECT 1 AS id, STRUCT("Alex" AS name, 30 AS age, "NYC" AS city) AS info UNION ALL
SELECT 1 AS id, STRUCT("Leo" AS name, 18 AS age, "Sydney" AS city) AS info UNION ALL
SELECT 1 AS id, STRUCT("Robert" AS name, 25 AS age, "Paris" AS city) AS info UNION ALL
SELECT 1 AS id, STRUCT("Mary" AS name, 28 AS age, "London" AS city) AS info UNION ALL
SELECT 1 AS id, STRUCT("Ralph" AS name, 45 AS age, "London" AS city) AS info
)
SELECT * FROM data
WHERE info.city = "London"
Notice that the STRUCT is named info and the data we accessed is city and used it in the WHERE clause.
Now, in order to delete the rows that contains an specific value within the STRUCT , in your case I assume it would be your_struct.column_1, you can use DELETE or MERGE and DELETE. I have saved the above data in a table to execute the below examples, which have the same output,
First method: DELETE
DELETE FROM `project.dataset.table`
WHERE info.city = "Sydney"
Second method: MERGE and DELETE
MERGE `project.dataset.table` a
USING (SELECT * from `project.dataset.table` WHERE info.city ="London") b
ON a.info.city =b.info.city
WHEN matched and b.id=1 then
Delete
And the output for both queries,
Row id info.name info.age info.city
1 1 Alex 30 NYC
2 1 Robert 25 Paris
3 1 Ralph 45 London
4 1 Mary 28 London
As you can see the row where info.city = "Sydney" was deleted in both cases.
It is important to point out that your data is excluded from your source table. Therefore, you should be careful.
Note: Since you want to run this process everyday, you could use Schedule Query within BigQuery Console, appending or overwriting the results after each run. Also, it is a good practice not deleting data from your source table. Thus, consider creating a new table from your source table without the rows you do not desire.

Replicating functionality of excel cell referencing (or calculations over multiple views)

I have a table with 3 columns that contains a number of data streams all in one table.
val_name is the name of the data stream, val_sequence is the incrementing sequence number and val contains the data. Combined name and sequence are like a composite index.
The existing val_name streams in this table are a, b. I would like users to be able to request stream c (which is not in the table), and the database to dynamically return a*b.
a*b in this case would be like multiplying two tables, one containing only val_name a, the other val_name b, and then joining on val_sequence (much like multiplying indexed python pandas series).
So the results would be:
val_sequence val_name val
0 c 80
1 c 5
The idea is that users should be able to request a or b or c and receive data, without needing to know that a and b hold data, and c only holds references. it's possible that some sequence numbers are missing both in the middle or at either end.
I haven't been able to figure out a good way how to provide this kind of flexibility. Are SQL views flexible enough for this? And if so could you give me a simple example? If not, what might be a workable alternative? Any database engine of your choice is fine.
For convenience, I am providing SQL code that creates a table and inserts above values, and creates two views. This doesn't do what I need it to do, but it's a start for those who want to give it a try.
CREATE TABLE IF NOT EXISTS valdb (
val_name VARCHAR(255),
val INT,
val_sequence int
);
INSERT into valdb (val_name, val, val_sequence) VALUES ("a",10,0);
INSERT into valdb (val_name, val, val_sequence) VALUES ("a", 1,1);
INSERT into valdb (val_name, val, val_sequence) VALUES ("b", 8,0);
INSERT into valdb (val_name, val, val_sequence) VALUES ("b", 5,1);
CREATE VIEW `a` AS SELECT val_name, val, val_sequence from valdb WHERE val_name = "a" ;
CREATE VIEW `b` AS SELECT val_name, val, val_sequence from valdb WHERE val_name = "b" ;
If, as you sample suggests, the sequence numbers are guaranteed to be the same for both streams, i.e. if and only if there exits n for a an n also exists for b, that would be an inner join on the sequence number and the * operator to get the multiplication.
CREATE VIEW c
AS
SELECT 'c' val_name,
a.val_sequence,
a.val * b.val val
FROM a
INNER JOIN b
ON a.val_sequence = b.val_sequence;
db<>fiddle (assuming MySQL from the syntax of the code you provided)
If the assumption doesn't hold true you'd need to define what should happen in such cases where it fails. E.g. whether to get the next available sequence number and whether a or b provides the "leading" sequence number or if val should be assumed to be 0 for missing sequence numbers, etc..

Search for element in array of composite types

Using PostgreSQL 9.0
I have the following table setup
CREATE TABLE person (age integer, last_name text, first_name text, address text);
CREATE TABLE my_people (mperson person[]);
INSERT INTO my_people VALUES(array[ROW(44, 'John', 'Smith', '1234 Test Blvd.')::person]);
Now, i want to be able to write a select statement that can search and compare values of my composite types inside my mperson array column.
Example:
SELECT * FROM my_people WHERE 20 > ANY( (mperson) .age);
However when trying to execute this query i get the following error:
ERROR: column notation .age applied to type person[], which is not a composite type
LINE 1: SELECT mperson FROM my_people WHERE 20 > ANY((mperson).age);
So, you can see i'm trying to test the values of the composite type inside my array.
I know, i'm not supposed to use arrays and composites in my tables, but this best suites our applications requirements.
Also, we have several nested composite arrays, so a generic solution that would allow me to search many levels would be appreciated.
The construction ANY in your case looks redundant. You can write the query that way:
SELECT * FROM my_people WHERE (mperson[1]).age < 20;
Of course, if you have multiple values in this array, that won't work, but you can't get the exact array element the other way neither.
Why do you need arrays at all? You can just write one element of type person per row.
Check also the excellent HStore module, which might better suit your generic needs.
Temporary test setup:
CREATE TEMP TABLE person (age integer, last_name text, first_name text
, address text);
CREATE TEMP TABLE my_people (mperson person[]);
-- test-data, demonstrating 3 different syntax styles:
INSERT INTO my_better_people (mperson)
VALUES
(array[(43, 'Stack', 'Over', '1234 Test Blvd.')::person])
,(array['(44,John,Smith,1234 Test Blvd.)'::person,
'(21,Maria,Smith,1234 Test Blvd.)'::person])
,('{"(33,John,Miller,12 Test Blvd.)",
"(22,Frank,Miller,12 Test Blvd.)",
"(11,Bodi,Miller,12 Test Blvd.)"}');
Call (almost the solution):
SELECT (p).*
FROM (
SELECT unnest(mperson) AS p
FROM my_people) x
WHERE (p).age > 33;
Returns:
age | last_name | first_name | address
-----+-----------+------------+-----------------
43 | Stack | Over | 1234 Test Blvd.
44 | John | Smith | 1234 Test Blvd.
key is the unnest() function, that's available in 9.0.
Your mistake in the example is that you forget about the ARRAY layer in between. unnest() returns one row per base element, then you can access the columns in the complex type as demonstrated.
Brave new world
IF you actually want a whole people instead of an individual that fits the criteria, I propose you add a primary key to the table and proceed as follows:
CREATE TEMP TABLE my_better_people (id serial, mperson person[]);
-- shortcut to populate the new world by emigration from the old world ;)
INSERT INTO my_better_people (mperson)
SELECT mperson FROM my_people;
Find individuals:
SELECT id, (p).*
FROM (
SELECT id, unnest(mperson) AS p
FROM my_better_people) x
WHERE (p).age > 20;
Find whole people (solution):
SELECT *
FROM my_better_people p
WHERE EXISTS (
SELECT 1
FROM (
SELECT id, unnest(mperson) AS p
FROM my_better_people
) x
WHERE (p).age > 20
AND x.id = p.id
);
You can do it without a primary key, but that would be foolish.

Fetch a single field from DB table into itab

I want to fetch the a field say excep_point from a transparent table z_accounts for the combination of company_code and account_number. How can I do this in ABAP SQL?
Assume that table structure is
|company_code | account_number | excep_point |
Assuming you have the full primary key...
data: gv_excep_point type zaccounts-excep_point.
select single excep_point
into gv_excep_point
from zaccounts
where company_code = some_company_code
and account_number = some_account_number.
if you don't have the full PK and there could be multiple values for excep_point
data: gt_excep_points type table of zaccounts-excep_point.
select excep_point
into table gt_excep_points
from zaccounts
where company_code = some_company_code
and account_number = some_account_number.
There is at least another variation, but those are 2 I use most often.
For information only. When you selects data into table you can write complex expressions to combine different fields. For example, you have internal table (itab) with two fields "A" and "B". And you are going to select data from DB table (dbtab) wich have 6 columns - "z","x","y","u","v","w". And for example each field is type char2 You aim to cimbine "z","x","y","u" in "A" field of internal table and "v","w" in "B" field. You can write simple code:
select z as A+0(2)
x as A+2(2)
y as A+4(2)
u as A+6(2)
v as B+0(2)
w as B+2(2) FROM dbtab
INTO CORRESPONDING FIELDS OF TABLE itab
WHERE <where condition>.
This simple code makes you job done very simple
In addition to Bryans answer, here is the official online documentation about Open SQL.