Display colon separated values in postgres - postgresql

I am using postgresql 8.1 and i dont have the new functions in that version. Please help me what to do in that case?
My first table is as follows
unit_office table:
Mandal_ids Name
82:05: test sample
08:20:16: test sample
Mandal Master table:
mandal_id mandal_name
08 Etcherla
16 Hiramandalam
20 Gara
Now when I say select * from unit_office it should display:
Mandal Name of office
Hiramandalam, Gara test sample
i.e in place of ids I want the corresponding names (which are in master table)separated by comma
I have a column in postgres which has colon separated ids. The following is one record from my table.
mandalid
18:82:14:11:08:05:20:16:83:37:23:36:15:06:38:33:26:30:22:04:03:
When I say select * from table, the mandalid column should display the names of the mandals in the id place separated by a comma.
Now i have the corresponding name for the id in a master table.
I want to display the names of the ids in the select query of the first table. like
my first table name is unit office. when i say select * from unit office, I want the names in the place of ids.

I suggest you redesign your tables, but if you cannot, then you may need to define a function, which will split the mandal_ids string into integers, and map them to names. I suggest you read the PostgreSQL documentation on creating functions. The "PL/pgSQL" language may be a good choice. You may use the functions string_to_array and array_to_string.
But if you can, I suggest you define your tables in the following way:
mandals:
id name
16 Hiramandalam
20 Gara
unit_offices:
id name
1 test sample
mandals_in_offices:
office_id mandal_id
1 16
1 20
The output from the following query should be what you need:
SELECT string_agg(m.name,',') AS mandal_names,
max(o.name) AS office_name
FROM mandals_in_offices i
INNER JOIN unit_offices o ON i.office_id = o.id
INNER JOIN mandals m ON i.mandal_id = m.id
GROUP BY o.id;
The function string_agg appeared in PostgreSQL version 9, so if you are using older version, you may need to write similar function yourself. I believe this will not be too hard.

Here's what we did in LedgerSMB:
created a function to do the concatenation
created a custom aggregate to do the aggregation.
This allows you to do this easily.
CREATE OR REPLACE FUNCTION concat_colon(TEXT, TEXT) returns TEXT as
$$
select CASE WHEN $1 IS NULL THEN $2 ELSE $1 || ':' || $2 END;
$$ language sql;
CREATE AGGREGATE concat_colon (
BASETYPE = text,
STYPE = text,
SFUNC = concat_colon
);
Then you can:
select concat_colon(mycol::text) from mytable;
Works just fine.

Related

Postgres Functions: Getting the Return Table Column Details

I feel the need to get the column names and data types of the table returned by any function that has a 'record' return data type, because...
A key process in an existing SQL Server-based system makes use of a stored procedure that takes a user-defined function as a parameter. An initial step gets the column names and types of the table returned by the function that was passed as a parameter.
In Postgres 13 I can use pg_proc.prorettype and the corresponding pg_type to find functions that return record types...that's a start. I can also use pg_get_function_result() to get the string containing the information I need. But, it's a string, and while I ultimately will have to assemble a very similar string, this is just one application of the info. Is there a tabular equivalent containing (column_name, data_type, ordinal_position), or do I need to do that myself?
Is there access to a composite data type the system may have created when such a function is created?
One option that I think will work for me, but I think it's a little weird, is to:
> create temp table t as select * from function() limit 0;
then look that table up in info_schema.columns, assemble what I need and drop the temp table...putting all of this into a function.
You can query the catalog table pg_proc, which contains all the required information:
SELECT coalesce(p.na, 'column' || p.i),
p.ty::regtype,
p.i
FROM pg_proc AS f
CROSS JOIN LATERAL unnest(
coalesce(f.proallargtypes, ARRAY[f.prorettype]),
f.proargmodes,
f.proargnames
)
WITH ORDINALITY AS p(ty,mo,na,i)
WHERE f.proname = 'interval_ok'
AND coalesce(p.mo, 'o') IN ('o', 't')
ORDER BY p.i;

How can I run a postgresql query over array of strings?

I'm writing a script which will take all tables from my schema and perform some actions on them. The tables that will be taken have same prefix and different suffix. Now, what I want to do is to declare an array at the beginning of the script, the array will contain all regex for all tables that I need, for example:
base_tables varchar[2] := ARRAY['table_name_format_2%',
'another_format_3%'];
Using this array, I would like to go through all the tables in my schema and take only those that match the name pattern in the array.
I tried to do this as such:
FOR table_item IN
SELECT table_name
FROM information_schema.tables
WHERE table_name LIKE IN base_tables
LOOP
---- Some code goes here -----
END LOOP;
The error I get is :
ERROR: syntax error at or near "IN"
What is the correct way to compare each table name, to the names in my array?
Thanks in advance.
demo:db<>fiddle
To get a match for an array element you have to use:
-- general case
WHERE element = ANY(ARRAY['elem1', 'elem2'])
-- your case
WHERE table_name = ANY(base_tables)
If you want to achieve a LIKE eehrm... like operation you'll need another way:
SELECT table_name
FROM information_schema.tables t
JOIN (SELECT unnest(base_tables) as name) bt
ON t.table_name LIKE bt.name
Joining tables against an unnested base_tables array (unnest expands an array to one row for each element). You can join with the LIKE operator.
demo:db<>fiddle

How to update column based on column name in postgres?

I've narrowed it down to two possibilities - DynamicSQL and using a case statement.
However, I've failed with both of these.
I simply don't understand dynamicSQL, and how I would use it in my case.
This is my attempt using case statements; one of many failed variations.
SELECT column_name,
CASE WHEN column_name = 'address' THEN (**update statement gives syntax error within here**)
END
FROM information_schema.columns
WHERE table_name = 'employees';
As an overview, I'm using Axios to talk to my Node server, which is making calls to my Heroku database using Massivejs.
Maybe this isn't the way to go - so here's my main problem:
I've ran into troubles because the values I'm planning on using as column names are sent to my server as strings. The exact call that I've been trying to use is
update employees
set $1 = $2
where employee_id = $3;
Once again, I'm passing into those using massive.
I get the error back { error: syntax error at or near "'address'"} because my incoming values are strings. My thought process was that the above statement would allow me to use variables because 'address' is encapsulated by quotes.
But alas, my thought process has failed me.
This seems to be close to answering my question, but I can't seem to figure out what to do in my case if using dynamic SQL.
How to use dynamic column names in an UPDATE or SELECT statement in a function?
Thanks in advance.
I will show you a way to do this by using a function.
First we create the employees table :
CREATE TABLE employees(
id BIGSERIAL PRIMARY KEY,
column1 TEXT,
column2 TEXT
);
Next, we create a function that requires three parameters:
columnName - the name of the column that needs to be updated
columnValue - the new value to which the column needs to be updated
employeeId - the id of the employee that will be updated
By using the format function we generate the update query as a string and use the EXECUTE command to execute the query.
Here is the code of the function.
CREATE OR REPLACE FUNCTION update_columns_on_employee(columnName TEXT, columnValue TEXT, employeeId BIGINT)
RETURNS VOID AS
$$
DECLARE update_statement TEXT := format('UPDATE EMPLOYEES SET %s = ''%s'' WHERE id = %L',columnName, columnValue, employeeId);
BEGIN
EXECUTE update_statement;
end;
$$ LANGUAGE plpgsql;
Now, lets insert some data into the employees table
INSERT INTO employees(column1, column2) VALUES ('column1_start_value','column2_start_value');
So now we currently have an employee with an id value of 1 who has 'column1_start_value' value for the column1, and 'column2_start_value' value for column2.
If we want to update the value of column2 from 'column2_start_value' to 'column2_new_value' all we have to do is execute the following call
SELECT * FROM update_columns_on_employee('column2','column2_new_value',1);

Create function/variable/parameter in pgAdmin with specific values

Not sure whether this is possible and what's the best way to do it, but I have a list of values (say it is 'ACBC', 'ADFC', 'AGGD' etc.) which grows over time. I want to use these values in pgADmin as a sort of variable/parameter for SQL statements; e.g:
Codes = {'ACBC', 'ADFC', 'AGGD'}
SQL: Statement => SELECT * FROM xxx WHERE SUBSTRING IN (Codes)
Is that somehow realizable, either with a variable, parameter, function or anyhing else?
I can think of the following options:
1) Create separate table
create table qry_params(prm_value varchar);
insert into qry_params values
('xxx'),
('yyy'),
('zzz');
select * from xxx where substring in (select prm_value from qry_params)
Whenever you have new parameter, you just need to add it to the table.
2) CTE at the top of query
Use query like:
with params (prm_value) as (select values ('xxx'), ('yyy'), ('zzz'))
select * from xxx where substring in (select prm_value from qry_params)
Whenever you have new parameter, you just need to add it to the CTE.

Split Cell using SSIS

I'm looking to use SSIS to transform the data held from a single source table. One of the cells has a string of characters. For example:
##/\/\/\/\/\##HHHHHHBBBB##/\/\/\/\/\
There's also another cell on the same row which contains a date.
Basically I want a each character within that string to be transferred to a new table as a row on it's own. The first two characters represent the date given in the other cell. The next two characters represent the following day and so on. So as well as having each character on it's own I would also want to increment the data and store that too.
Any idea how I would go about doing this or even if SSIS is the correct tool to be using.
Many Thanks
I wonder if you'd be better running this through a split-string function in SQL first? That way you'l be getting rows for each character along-side the date, and then you can just output it straight to a destination.
I've created a function to facilitate this:
CREATE FUNCTION [dbo].[udf_SplitStringIntoRows](#text varchar(max))
RETURNS #tbl TABLE ([value] char(1) NOT NULL)
AS
BEGIN
WHILE len(#text) > 0
BEGIN
INSERT INTO #tbl
SELECT left(#text,1)
SET #text = RIGHT(#text,len(#text)-1)
END
RETURN
END
Then, to test the data i created a quick temp table with your data in:
DECLARE #source as TABLE([value] varchar(max), [date] datetime)
INSERT INTO #source
SELECT '##/\/\/\/\/\##HHHHHHBBBB##/\/\/\/\/\', getdate()
UNION
SELECT '##/\/\/\/\/\##HHHHHHBBBB##/\/\/\/\/\', getdate()+1
UNION
SELECT '##/\/\/\/\/\##HHHHHHBBBB##/\/\/\/\/\', getdate()+2
Then cross applied the function to this dataset:
SELECT d.[value], s.date
FROM #source s
CROSS APPLY dbo.[udf_SplitStringIntoRows](s.value) d
Which should give you the source dataset you require to further process in SSIS.