select a column with how many same value present - sql

i have string data on my column
------------
name
------------
john-yolo
john-yolo
john-yolo
felix-goran
carine-carin
carine-carin
i want to select name column with how many times the name present
ex :
------------
name
------------
john-yolo-1
john-yolo-2
john-yolo-3
felix-goran-1
carine-carin-1
carine-carin-2
how can i produce data like that?

MaraiDB supports ROW_NUMBER
CREATE TABLE test
(`name` varchar(12))
;
INSERT INTO test
(`name`)
VALUES
('john-yolo'),
('john-yolo'),
('john-yolo'),
('felix-goran'),
('carine-carin'),
('carine-carin')
;
SELECT CONCAT(name,'-', ROW_NUMBER() OVER(PARTITION BY name)) as name FROM test
| name |
| :------------- |
| carine-carin-1 |
| carine-carin-2 |
| felix-goran-1 |
| john-yolo-1 |
| john-yolo-2 |
| john-yolo-3 |
db<>fiddle here

Related

Snowflake Create View with JSON (VARIANT) field as columns with dynamic keys

I am having a problem creating VIEWS with Snowflake that has VARIANT field which stores JSON data whose keys are dynamic and keys definition is stored in another table. So I want to create a VIEW that has dynamic columns based on the foreign key.
Here are my table looks like:
companies:
| id | name |
| -- | ---- |
| 1 | Company 1 |
| 2 | Company 2 |
invoices:
| id | invoice_number | custom_fields | company_id |
| -- | -------------- | ------------- | ---------- |
| 1 | INV-01 | {"1": "Joe", "3": true, "5": "2020-12-12"} | 1 |
| 2 | INV-01 | {"2":"Hello", "4": 1000} | 2 |
customization_fields:
| id | label | data_type | company_id |
| -- | ----- | --------- | ---------- |
| 1 | manager | text | 1 |
| 2 | reference | text | 2 |
| 3 | emailed | boolean | 1 |
| 4 | account | integer | 2 |
| 5 | due_date | date | 1 |
So I want to create a view for getting each companies invoices something like:
CREATE OR REPLACE VIEW companies_invoices AS SELECT * FROM invoices WHERE company_id = 1
which should get a result like below:
| id | invoice_number | company_id | manager | emailed | due_date |
| -- | -------------- | ---------- | ------- | ------- | -------- |
| 1 | INV-01 | 1 | Joe | true | 2020-12-12 |
So my challenge above here is I cannot make sure the keys when I write the query. If I know that I could write
SELECT
id,
invoice_number,
company_id,
custom_fields:"1" AS manager,
custom_fields:"3" AS emailed,
custom_fields:"5" AS due_date
FROM invoices
WHERE company_id = 1
These keys and labels are written in the customization_fields table, so I tried different ways and I am not able to do that.
So could anyone tell me if we can do or not? If we can please give me an example so it would really help.
You cannot do what you want to do with a view. A view has a fixed set of columns and they have specific types. Retrieving a dynamic set of columns requires some other mechanism.
If you're trying to change the number of columns or the names of the columns based on the rows in the customization_fields table, you can't do it in a view.
If you have a defined schema and just need to grab dynamic JSON properties, you may want to consider looking into Snowflake's GET function. It allows you to get any part of a JSON using a string for the path rather than using a literal path in the SQL statement. For example:
create temp table foo(v variant);
insert into foo select parse_json('{ "name":"John", "age":30, "car":null }');
-- This uses a literal path in the SQL to get to a JSON property
select v:name::string as first_name from foo;
-- This uses the GET function to get the value from a path in a string
select get(v, 'name')::string as first_name from foo;
You can replace the 'name' in the second parameter of the GET function with the value stored in the customization_fields table.
In SF, You will have to use a Stored Proc function to retrieve the dynamic set of columns

How do I get values that are themselves not unique, but are linked to unique fields(in SQL)?

I can't give the actual table, but my problem is something like this:
Assuming that there is a table called Names with entries like these:
+--------------+
| name | id |
+--------------+
| Jack | 1001 |
| Jack | 1022 |
| John | 1010 |
| Boris | 1092 |
+--------------+
I need to select all the unique names from that table, and display them(only names, not ids). But if I do:
SELECT DISTINCT name FROM Names;
Then it will return:
+-------+
| name |
+-------+
| Jack |
| John |
| Boris |
+-------+
But as you can see in the table, the 2 people named "Jack" are different, since they have different ids. How do I get an output like this one:
+-------+
| name |
+-------+
| Jack |
| Jack |
| John |
| Boris |
+-------+
?
Assuming that some ids can or will be repeated(not marked primary key in question)
Also, in the question, the result will have 1 column and some number of rows(exact number is given, its 18,013). Is there a way to check if I have the right number of rows? I know I can use COUNT(), but while selecting the unique values I used GROUP BY, so using COUNT() would return the counts for how many names have that unique id, as in:
SELECT name FROM Names GROUP BY id;
+------------------+
| COUNT(name) | id |
+------------------+
| 2 | 1001 |
| 1 | 1022 |
| 1 | 1092 |
| 3 | 1003 |
+------------------+
So, is there something to help me verify my output?
You can use group by:
select name
from names
group by name, id;
You can get all the distinct persons with:
SELECT DISTINCT name, id
FROM names
and you can select from the above query only the names:
SELECT name
FROM (
SELECT DISTINCT name, id
FROM names
)

Postgresql - How to remove last one from array_agg() in one select query?

I have a special need with below table
Table "public.skill_name"
Column | Type | Collation | Nullable | Default
----------+---------+-----------+----------+---------
position | integer | | not null |
value | text | | not null |
id | text | | not null |
skill | text | | |
Indexes:
"skill_name.id" UNIQUE, btree (id)
Foreign-key constraints:
"skill_name_skill_fkey" FOREIGN KEY (skill) REFERENCES skill(id) ON DELETE SET NULL
and some sample data like below:
position | value | id | skill
----------+---------------------------------------------------------------------------------------+-----------------------------+-----------------------------
1000 | Python | ck5bxmk67101790acuf05cikujw | ck5bxmk62101789acuf7pj1qmj6
2000 | Python Language | ck5bxmk69101791acufih7mc6u6 | ck5bxmk62101789acuf7pj1qmj6
3000 | Stdlib | ck5bxmk6c101792acuflzcu2avg | ck5bxmk62101789acuf7pj1qmj6
4000 | functools | ck5bxmk6e101793acuf42ih0evn | ck5bxmk62101789acuf7pj1qmj6
5000 | lru_cache | ck5bxmk6g101794acuf690rjgzp | ck5bxmk62101789acuf7pj1qmj6
1000 | Python | ck5bxysvp102005acuf6unt4cb7 | ck2wk5gba044342xbyaulv17i
2000 | Python Language | ck5bxysvs102012acuf5862l0gx | ck2wk5gba044342xbyaulv17i
3000 | Python Syntax | ck5bxysvu102021acufjcmxi1ij | ck2wk5gba044342xbyaulv17i
4000 | Classes | ck5bxysvx102030acufbaz3kml3 | ck2wk5gba044342xbyaulv17i
5000 | metaclasses | ck5bxysvz102037acufa5lmbuhj | ck2wk5gba044342xbyaulv17i
The requirement is to generate a result like below(NOTE: The last one group by skill been excluded in column path)
skill | path
-----------------------------+---------------------------------------------------------------------------------------
ck5bxmk62101789acuf7pj1qmj6 | Python,Python Language,Stdlib,functools
ck2wk5gba044342xbyaulv17i | Python,Python Language,Python Syntax,Classes
I have below sql but it does not work, it complains more than one row returned by a subquery used as an expression
SELECT
skill,
ARRAY_REMOVE(
ARRAY_AGG(value),
(
SELECT
skill_name.value
FROM (
SELECT
*,
skill AS skill_id,
LAST_VALUE(position) OVER (
PARTITION BY skill
ORDER BY position
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS last_pos
FROM skill_name
) skill_name
WHERE last_pos=position
GROUP BY skill_name.value
)
) as path
FROM skill_name
GROUP BY skill;
I do not know how to fix that, could any one help?
You could use row_number() to locate and eliminate the last value from the resultset before aggregating:
select skill, array_agg(value order by position) path
from (
select t.*, row_number() over(partition by skill order by position desc) rn
from mytable t
) t
where rn > 1
group by skill
Postgres has pretty sophisticated array functions. You don't need a subquery to do this:
select skill,
(array_agg(value order by position))[1:count(*) - 1] as path
from t
group by skill

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.