How to update JSONB column with value coming from another table column in PostgreSQL - postgresql

I have a source table, which lists like below:
public.source
Id | part_no | category
1 | 01270-4 | Landscape
2 | 01102-3 | Sports
Then, I have target table with jsonb column (combinations) , which list like below;
public.target
Id | part_no | combinations
7 | 01270-4 | {"subject":""}
8 | 01102-3 | {"subject":""}
My problem is - how I can update the target table with jsonb column (combinations) with the values coming from source table using the part_no column?
Output like:
Id | part_no | combinations
7 | 01270-4 | {"subject":"Landscape"}
8 | 01102-3 | {"subject":"Sports"}
I tried below but giving error:
UPDATE public.target t
SET combinations = jsonb_set(combinations,'{subject}','s.category',false)
FROM public.source s
WHERE s.part_no = t.part_no;
ERROR: invalid input syntax for type json
LINE 2: SET combinations = jsonb_set(combinations,'{subject}', 's.categor...
^
DETAIL: Token "s" is invalid.
CONTEXT: JSON data, line 1: s...
SQL state: 22P02
Character: 77

You should use to_jsonb function to convert s.category to JSON
Demo
UPDATE public.target t
SET combinations = jsonb_set(combinations,'{subject}',to_jsonb(s.category),false)
FROM public.source s
WHERE s.part_no = t.part_no
Or you can use sample structure for join and update two JSON field:
Demo
UPDATE public.target t
SET combinations = combinations || jsonb_build_object('subject', s.category)
FROM public.source s
WHERE s.part_no = t.part_no

Related

What is the seq_name column in the ag_label table?

I'm working on a new feature that involves labels for Apache AGE and I'm looking for tools with which I can work with.
In psql interface, when you input the command SELECT * FROM ag_catalog.ag_label; the following output is shown:
name | graph | id | kind | relation | seq_name
------------------+--------+----+------+-----------------------+-------------------------
_ag_label_vertex | 495486 | 1 | v | test._ag_label_vertex | _ag_label_vertex_id_seq
_ag_label_edge | 495486 | 2 | e | test._ag_label_edge | _ag_label_edge_id_seq
vtx_label | 495486 | 3 | v | test.vtx_label | vtx_label_id_seq
elabel | 495486 | 4 | e | test.elabel | elabel_id_seq
I came across this and wasn't able to figure out what kind of data I can retrieve from it, what is it used for or how can it help me.
Can you explain the seq_name column?
Seq_name refers to sequences. Sequences are single-row tables that can be thought of as 'number generators' that start at some minimum integer value and then increment as they are 'consumed'.
A sequence that is associated with a column can be used to assign values to it. For example, 'mytable_seq_id' associated with column 'id' in a particular table 'mytable' might start at 1. Then as you add more entries to mytable, the 'id' column begins to increment to 2,3 and so on.
Postgres docs on creating sequences:
https://www.postgresql.org/docs/current/sql-createsequence.html
As for AGE, here's a comment taken directly out of the 'graph_commands.c' source file. It describes how sequences are used to generate labels ids.
static Oid create_schema_for_graph(const Name graph_name)
{
char *graph_name_str = NameStr(*graph_name);
CreateSchemaStmt *schema_stmt;
CreateSeqStmt *seq_stmt;
TypeName *integer;
DefElem *data_type;
DefElem *maxvalue;
DefElem *cycle;
Oid nsp_id;
/*
* This is the same with running the following SQL statement.
*
* CREATE SCHEMA `graph_name`
* CREATE SEQUENCE `LABEL_ID_SEQ_NAME`
* AS integer
* MAXVALUE `LABEL_ID_MAX`
* CYCLE
*
* The sequence will be used to assign a unique id to a label in the graph.
*
* schemaname doesn't have to be graph_name but the same name is used so
* that users can find the backed schema for a graph only by its name.
*
* ProcessUtilityContext of this command is PROCESS_UTILITY_SUBCOMMAND
* so the event trigger will not be fired.
*/
Note that sequences are used in other functions in the AGE internals as well, and the above function is just one example.

How to use dynamic table name for sub query where the dynamic value coming from its own main query in PostgreSQL?

I have formed this query to get the desired output mentioned below:
select tbl.id, tbl.label, tbl.input_type, tbl.table_name
case when tbl.input_type = 'dropdown' or tbl.input_type = 'searchable-dropdown'
then (select json_agg(opt) from tbl.table_name) as opt) end as options
from mst_config as tbl;
I want output like below:
id | label | input_type | table_name | options
----+----------------------------------------------------+---------------------+-------------------------+-----------------------------------------------------------
1 | Gender | dropdown | mst_gender | [{"id":1,"label":"MALE"},
| | | | {"id":2,"label":"FEMALE"}]
2 | SS | dropdown | mst_ss | [{"id":1,"label":"something"},
| | | | {"id":2,"label_en":"something"}]
But, I'm facing a problem while using,
select json_agg(opt) from tbl.table_name) as opt
In the above part "tbl.table_name", I wanted to use it as dynamic table name but it's not working.
Then, I have searched a lot and found something like Execute format('select * from %s', table_name), where tablename is the dynamic table name. I have even tried the same with postgres function.
But I faced an issue again while using the format method. The reason is I want to use the variable for which the value needs to come from its own main query value instead of already having it in a variable. so this one was also not working.
I would really appreciate if anyone can help me out on this. Also if there are any other possibilities available to achieve this output, help me on that as well.

Query a PostgreSQL view created by SQLAcodegen

I have a useful PostgreSQL view, generated by a JOIN query:
\d very_useful_view;
View "public.very_useful_view"
Column | Type | Modifiers
-------------+-------------+-----------
tree_id | dom_treeid |
title | text |
grass_id | dom_grass |
name | text |
street_uuid | uuid |
The view was modeled by SQLAcodegen to the following object:
t_very_useful_view = Table(
'very_useful_view', metadata,
Column('tree_id', String),
Column('title', Text),
Column('grass_id', Text),
Column('name', Text),
Column('street_uuid', UUID)
)
Normal query works as expected:
print session.query(t_very_useful_view).all()
However, filtering -
print session.query(t_very_useful_view).\
filter(t_very_useful_view.tree_id == some_tree_id).\
all()
Raises:
AttributeError: 'Table' object has no attribute 'tree_id'
Any idea what am I missing with the view mapping?
The columns of a Table object should be accessed with the columns property:
print session.query(t_very_useful_view).\
filter(t_very_useful_view.columns.tree_id == some_tree_id).\
all()
This contrasts with subclasses of declarative_base(), which expose columns as root-level object properties.

Split a string and populate a table for all records in table in SQL Server 2008 R2

I have a table EmployeeMoves:
| EmployeeID | CityIDs
+------------------------------
| 24 | 23,21,22
| 25 | 25,12,14
| 29 | 1,2,5
| 31 | 7
| 55 | 11,34
| 60 | 7,9,21,23,30
I'm trying to figure out how to expand the comma-delimited values from the EmployeeMoves.CityIDs column to populate an EmployeeCities table, which should look like this:
| EmployeeID | CityID
+------------------------------
| 24 | 23
| 24 | 21
| 24 | 22
| 25 | 25
| 25 | 12
| 25 | 14
| ... and so on
I already have a function called SplitADelimitedList that splits a comma-delimited list of integers into a rowset. It takes the delimited list as a parameter. The SQL below will give me a table with split values under the column Value:
select value from dbo.SplitADelimitedList ('23,21,1,4');
| Value
+-----------
| 23
| 21
| 1
| 4
The question is: How do I populate EmployeeCities from EmployeeMoves with a single (even if complex) SQL statement using the comma-delimited list of CityIDs from each row in the EmployeeMoves table, but without any cursors or looping in T-SQL? I could have 100 records in the EmployeeMoves table for 100 different employees.
This is how I tried to solve this problem. It seems to work and is very quick in performance.
INSERT INTO EmployeeCities
SELECT
em.EmployeeID,
c.Value
FROM EmployeeMoves em
CROSS APPLY dbo.SplitADelimitedList(em.CityIDs) c;
UPDATE 1:
This update provides the definition of the user-defined function dbo.SplitADelimitedList. This function is used in above query to split a comma-delimited list to table of integer values.
CREATE FUNCTION dbo.fn_SplitADelimitedList1
(
#String NVARCHAR(MAX)
)
RETURNS #SplittedValues TABLE(
Value INT
)
AS
BEGIN
DECLARE #SplitLength INT
DECLARE #Delimiter VARCHAR(10)
SET #Delimiter = ',' --set this to the delimiter you are using
WHILE len(#String) > 0
BEGIN
SELECT #SplitLength = (CASE charindex(#Delimiter, #String)
WHEN 0 THEN
datalength(#String) / 2
ELSE
charindex(#Delimiter, #String) - 1
END)
INSERT INTO #SplittedValues
SELECT cast(substring(#String, 1, #SplitLength) AS INTEGER)
WHERE
ltrim(rtrim(isnull(substring(#String, 1, #SplitLength), ''))) <> '';
SELECT #String = (CASE ((datalength(#String) / 2) - #SplitLength)
WHEN 0 THEN
''
ELSE
right(#String, (datalength(#String) / 2) - #SplitLength - 1)
END)
END
RETURN
END
Preface
This is not the right way to do it. You shouldn't create comma-delimited lists in SQL Server. This violates first normal form, which should sound like an unbelievably vile expletive to you.
It is trivial for a client-side application to select rows of employees and related cities and display this as a comma-separated list. It shouldn't be done in the database. Please do everything you can to avoid this kind of construction in the future. If at all possible, you should refactor your database.
The Right Answer
To get the list of cities, properly expanded, from a table containing lists of cities, you can do this:
INSERT dbo.EmployeeCities
SELECT
M.EmployeeID,
C.CityID
FROM
EmployeeMoves M
CROSS APPLY dbo.SplitADelimitedList(M.CityIDs) C
;
The Wrong Answer
I wrote this answer due to a misunderstanding of what you wanted: I thought you were trying to query against properly-stored data to produce a list of comma-separated CityIDs. But I realize now you wanted the reverse: to query the list of cities using existing comma-separated values already stored in a column.
WITH EmployeeData AS (
SELECT
M.EmployeeID,
M.CityID
FROM
dbo.SplitADelimitedList ('23,21,1,4') C
INNER JOIN dbo.EmployeeMoves M
ON Convert(int, C.Value) = M.CityID
)
SELECT
E.EmployeeID,
CityIDs = Substring((
SELECT ',' + Convert(varchar(max), CityID)
FROM EmployeeData C
WHERE E.EmployeeID = C.EmployeeID
FOR XML PATH (''), TYPE
).value('.[1]', 'varchar(max)'), 2, 2147483647)
FROM
(SELECT DISTINCT EmployeeID FROM EmployeeData) E
;
Part of my difficulty in understanding is that your question is a bit disorganized. Next time, please clearly label your example data and show what you have, and what you're trying to work toward. Since you put the data for EmployeeCities last, it looked like it was what you were trying to achieve. It's not a good use of people's time when questions are not laid out well.

Selection formula excluding rows with columns having null values

I have a strange issue. I have a report CR. In the Selection Formula I do a test on two fields. The test is simple like that : {field_City} = 'Paris' OR {field_Country} = 'France'.
This is a sample of the data in my table:
|---------------|---------------|---------------|
| ID_Record | Country | City |
|---------------|---------------|---------------|
| 1 | null | Paris |
|---------------|---------------|---------------|
| 2 | France | null |
|---------------|---------------|---------------|
| 3 | France | Paris |
|---------------|---------------|---------------|
The result of the Selection should be the 3 records, however it's excluding the 2 first rows where there is a null value in one of the columns. Then I changed the Selection Formula like this to consider null values too : ({field_City} = 'Paris' AND (isnull({field_Country}) OR not(isnull({field_Country})))) OR ({field_Country} = 'France' AND (isnull({field_City}) OR not(isnull({field_City})))) but I am still getting only the last record ! To ensure myself that my code is correct, I generated the sql query via the option in CR 'Show sql query', then i've added a WHERE clause in which I wrote the same condition that i've put in the Selection Formula, and...... it gave me the 3 records ! Unfortunately I can't work with the sql query, I have to find out why the formula is excluding the records that have a null value in one of the columns :( I hope that you can help me. Thanks a lot !
This is the solution: ((isnull({field_Country}) AND {field_City} = 'Paris') OR (isnull({field_City}) AND {field_Country} = 'France') OR (not(isnull({field_Country})) AND {field_City} = 'Paris') OR (not(isnull({field_City})) AND {field_Country} = 'France')) , Thank you so much Craig!
You need to test for null values first:
( Not(Isnull({field_Country})) AND {field_Country}='France' )
OR
( Isnull({field_Country}) AND {field_City}='Paris' )