Split column values in postgres - sql

I have one table with two columns id and data. The values in the table are as follows:
id|data|
1 |A,B |
2 |B,C |
3 |C,D |
4 |D,A |
5 |E,C |
I need number of A,B,C,D,E present in the table as follows. Please note: columns are dynamic means they are dependent upon the values in the data column from the table:
A|B|C|D|E|
2|2|3|2|1|
And I have written the following query:
SELECT id,s.data
FROM my_table t,
unnest(string_to_array(t.data, ',')) s(data);
The output is given as follows:
id|data|
1 | A |
1 | A |
1 | A |
1 | A |
1 | A |
1 | A |
1 | A |
1 | A |

Please find the query which provide exact output which you want.
select * from crosstab ('SELECT ''Total'':: text, s.data, count(*)::int
FROM my_table t, unnest(string_to_array(t.data, '','')) s(data)
group by s.data') as ct(Total text, A int, B int, C int, D int, E int)
Please create extension tablefunc (if not created).

Related

How to select properties of arrays of indeterminate size (SQL Server)

I have a table of arrays, and would like to return a list of items.
| table |
|---------------------------------------|
| [{"item": 1},{"item": 2},{"item": 3}] |
| [{"item": 4},{"item": 5},{"item": 6}] |
| [{"item": 7},{"item": 8},{"item": 9}] |
Example Query
The following method will return a wide table of items, but it doesn't scale well.
select
json_value([table], '$[0].item'),
json_value([table], '$[1].item'),
json_value([table], '$[2].item')
from someTable;
How can I select properties of arrays of indeterminate size? (like 100)
Desired Output
| items |
|-------|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
You need to use OPENJSON to achieve this. Also, as I note, you should choose a different name than Table for a column's name. TABLE is a reserved key word and it's confusing as a COLUMN is not a TABLE.
WITH VTE AS(
SELECT *
FROM (VALUES(N'[{"item": 1},{"item": 2},{"item": 3}]'),
(N'[{"item": 4},{"item": 5},{"item": 6}]'),
(N'[{"item": 7},{"item": 8},{"item": 9}]'))V([Table])) --Table isn't a good choice of a came for a column.
--TABLE is a reserved keyword.
SELECT T.item
FROM VTE V
CROSS APPLY OPENJSON(V.[Table]) --Table isn't a good choice of a came for a column. TABLE is a reserved keyword.
WITH(item int) T;

How do I update a column from a table with data from a another column from this same table?

I have a table "table1" like this:
+------+--------------------+
| id | barcode | lot |
+------+-------------+------+
| 0 | ABC-123-456 | |
| 1 | ABC-123-654 | |
| 2 | ABC-789-EFG | |
| 3 | ABC-456-EFG | |
+------+-------------+------+
I have to extract the number in the center of the column "barcode", like with this request :
SELECT SUBSTR(barcode, 5, 3) AS ToExtract FROM table1;
The result:
+-----------+
| ToExtract |
+-----------+
| 123 |
| 123 |
| 789 |
| 456 |
+-----------+
And insert this into the column "lot" .
follow along the lines
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
i.e in your case
UPDATE table_name
SET lot = SUBSTR(barcode, 5, 3)
WHERE condition;(if any)
UPDATE table1 SET Lot = SUBSTR(barcode, 5, 3)
-- WHERE ...;
Many databases support generated (aka "virtual"/"computed" columns). This allows you to define a column as an expression. The syntax is something like this:
alter table table1 add column lot varchar(3) generated always as (SUBSTR(barcode, 5, 3))
Using a generated column has several advantages:
It is always up-to-date.
It generally does not occupy any space.
There is no overhead when creating the table (although there is overhead when querying the table).
I should note that the syntax varies a bit among databases. Some don't require the type specification. Some use just as instead of generated always as.
CREATE TABLE Table1(id INT,barcode varchar(255),lot varchar(255))
INSERT INTO Table1 VALUES (0,'ABC-123-456',NULL),(1,'ABC-123-654',NULL),(2,'ABC-789-EFG',NULL)
,(3,'ABC-456-EFG',NULL)
UPDATE a
SET a.lot = SUBSTRING(b.barcode, 5, 3)
FROM Table1 a
INNER JOIN Table1 b ON a.id=b.id
WHERE a.lot IS NULL
id | barcode | lot
-: | :---------- | :--
0 | ABC-123-456 | 123
1 | ABC-123-654 | 123
2 | ABC-789-EFG | 789
3 | ABC-456-EFG | 456
db<>fiddle here

Join two tables returning all rows as single row from the second table

I want to get data in a single row from two tables which have one to many relation.
Primary table
Secondary table
I know that for each record of primary table secondary table can have maximum 10 rows. Here is structure of the table
Primary Table
-------------------------------------------------
| ImportRecordId | Summary |
--------------------------------------------------
| 1 | Imported Successfully |
| 2 | Failed |
| 3 | Imported Successfully |
-------------------------------------------------
Secondary table
------------------------------------------------------
| ImportRecordId | CodeName | CodeValue |
-------------------------------------------------------
| 1 | ABC | 123456A |
| 1 | DEF | 8766339 |
| 1 | GHI | 887790H |
------------------------------------------------------
I want to write a query with inner join to get data from both table in a way that from secondary table each row should be treated as column instead showing as multiple row.
I can hard code 20 columns names(as maximum 10 records can exist in secondary table and i want to display values of two columns in a single row) so if there are less than 10 records in the secondary table all other columns will be show as null.
Here is expected Output. You can see that for first record in primary table there was only three rows that's why two required columns from these three rows are converted into columns and for all others columns values are null.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| ImportRecordId | Summary | CodeName1 | CodeValue1 | CodeName2 | CodeValue2 | CodeName3 | CodeValue3 | CodeName4 | CodeValue4| CodeName5 | CodeValue5| CodeName6 | CodeValue6| CodeName7 | CodeValue7 | CodeName8 | CodeValue8 | CodeName9 | CodeValue9 | CodeName10 | CodeValue10|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 1 | Imported Successfully | ABC | 123456A | DEF | 8766339 | GHI | 887790H | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Here is my simple SQL query which return all data from both tables but instead multiple rows from secondary table i want to get them in a single row like above result set.
Select p.ImportRecordId,p.Summary,s.*
from [dbo].[primary_table] p
inner join [dbo].[secondary_table] s on p.ImportRecordId = s.ImportRecordId
The following uses Row_Number(), a JOIN and a CROSS APPLY to create the source of the PIVOT
You'll have to add the CodeName/Value 4...10
Example
Select *
From (
Select A.[ImportRecordId]
,B.Summary
,C.*
From (
Select *
,RN = Row_Number() over (Partition by [ImportRecordId] Order by [CodeName])
From Secondary A
) A
Join Primary B on A.[ImportRecordId]=B.[ImportRecordId]
Cross Apply (values (concat('CodeName' ,RN),CodeName)
,(concat('CodeValue',RN),CodeValue)
) C(Item,Value)
) src
Pivot (max(value) for Item in (CodeName1,CodeValue1,CodeName2,CodeValue2,CodeName3,CodeValue3) ) pvt
Returns
ImportRecordId Summary CodeName1 CodeValue1 CodeName2 CodeValue2 CodeName3 CodeValue3
1 Imported Successfully ABC 123456A DEF 8766339 GHI 887790H

Pivot SSRS Dataset

I have a dataset which looks like so
ID | PName | Node | Val |
1 | Tag | Name | XBA |
2 | Tag | Desc | Dec1 |
3 | Tag | unit | Int |
6 | Tag | tids | 100 |
7 | Tag | post | AAA |
1 | Tag | Name | XBB |
2 | Tag | Desc | Des9 |
3 | Tag | unit | Float |
7 | Tag | post | BBB |
6 | Tag | tids | 150 |
I would like the result in my report to be
Name | Desc | Unit | Tids | Post |
XBA | Dec1 | int | 100 | AAA |
XBB | Des9 | Float | 150 | BBB |
I have tried using a SSRS Matrix with
Row: PName
Data: Node
Value: Val
The results were simply one row with Name and next row with desc and next with unit etc. Its not all in the same rows and also the second row was missing. This is possibly because there is no grouping on the dataset.
What is a good way of achieving the expected results?
I would not recommend this for a production scenario but if you need to knock out a report quickly or something you can try this. I would just not feel comfortable that the order of the records you get will always be what you expect.
You COULD try to insert the results of the SP into a table (regular table, temp table, table variable...doesn't matter really as long as you can get an identity column added). Assuming that the rows always come out in the correct order (which is probably not a valid assumption 100% of the time) then add an identity column on the table to get a unique row number for each row. From there you should be able to write some math logic to "group" your values together and then pivot out what you want.
create table #temp (ID int, PName varchar(100), Node varhar(100), Val varchar(100))
insert #temp exec (your stored proc)
alter table #temp add UniqueID int identity
then use UniqueID (modulo on 5 perhaps?) to group records together and then pivot

How to join table with dynamic identifier in postgres?

I have a table name table containing two columns foreign_table_name, and foreign_key.
Is it possible to write a SELECT query that would JOIN values of this table and the table which name is specified in the column foreign_table_name ?
For instance, if we know that all possible targetted foreign tables have a name field, I would like to know if I could write something that would:
SELECT table.foo, table.bar, foreign_table.name
FROM table
JOIN $foreign_table AS foreign_table
ON (foreign_table.id = table.foreign_key
$foreign_table = table.foreign_table);
Any solution using PlpgSQL is of course accepted.
Here's a simple content:
Table ``table``
------------------------------------------------
| foo | bar | foreign_table_name | foreign_key |
------------------------------------------------
| A | 1 | fruits | 8 |
| B | 2 | vegetable | 5 |
------------------------------------------------
Table ``fruit``
---------------
| id | name |
---------------
| 8 | apple |
---------------
Table ``vegetable``
----------------
| id | name |
----------------
| 5 | carrot |
----------------
The expected result table would be:
----------------------
| foo | bar | name |
----------------------
| A | 1 | apple |
| B | 2 | carrot |
----------------------
EDIT: I added the full table example in an attempt to be clearer.
It's usually way easier to do this sort of thing on the client side, but if you want it's possible with PL/PgSQL, e.g.
CREATE OR REPLACE FUNCTION dynamic_call(tblname text)
RETURNS TABLE (foo int, bar text, fname text)
AS $$
BEGIN
RETURN QUERY EXECUTE format('
SELECT t.foo, table.bar, f."name"
FROM mytable t
JOIN %I AS f ON (f.id = t.foreign_key);', tblname);
END;
$$ LANGUAGE plpgsql;
For more information, see the PL/PgSQL documentation.