I have tried to find the best solution for my "problem" but my SQL knowledge is limited so I'm asking for your help.
I currently have a "main" table named Project and its primary key (ProjectId) is use in other tables like "Description" (see below)
Table "Project" :
+-----------+----------+-----------+
| ProjectId | P_Field1 | P_Field2 |
+-----------+----------+-----------+
| 1 | val1 | val2 |
+-----------+----------+-----------+
Table "Descriptive" :
+-----------+----------+-----------+
| ProjectId | D_Field1 | D_Field2 |
+-----------+----------+-----------+
| 1 | valA | valB |
+-----------+----------+-----------+
I'm trying to write a stored procedure that selects all the datas with its fieldname of multiple tables, based on a "ProjectId", then the output result would be :
Sotred Procedure Result with parameter #ProjectId = 1 :
+-----------+----------+
| FieldName | Value |
+-----------+----------+
| P_Field1 | val1 |
+-----------+----------+
| P_Field2 | val2 |
+-----------+----------+
| D_Field1 | valA |
+-----------+----------+
| D_Field2 | valB |
+-----------+----------+
A friend told me that the SQL "PIVOT" function could help me but I never have used this function and my search on it really didn't help me because it is often used with "SUM", "MAX" etc and I don't need that.
Thanks in advance.
You want unpivot, not pivot, and a union
select fieldname, value from [project]
unpivot (value for fieldname in ([p_field1],[p_field2])) p
where projectid=1
union all
select fieldname, value from [descriptive]
unpivot (value for fieldname in ([d_field1],[d_field2])) p
where projectid=1
Related
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
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
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
I'm currently working on a stored procedure in T-SQL on SQL Server 2012. I need to merge 2 tables without an Id. The Id will be created on the insert into the first table. My problem is kind of tricky, thus maybe you can help me :)
In the stored procedure, the import table looks the following way:
CREATE TYPE [MySchema].[Target] AS TABLE
(
IsPrivate BIT,
IsPublic BIT,
CountryId VARCHAR(100)
);
GO
#TARGETS MySchema.Target READONLY
Some possible values for the import #Targets:
IsPrivate | IsPublic | CountryId |
----------+----------+-------------+
1 | 0 | CA,FR |
0 | 1 | US,GB |
Desired output: these #Targets I need to split up into 2 tables, Target and Country:
Create new entries in Target :
TargetId | IsPrivate | IsPublic |
---------+-----------+----------+
23 | 1 | 1 |
24 | 0 | 0 |
Split up the CountryId into it's own table, Country and add the TargetId:
Id | TargetId | CountryId |
---+----------+-----------+
1 | 23 | CA |
2 | 23 | FR |
3 | 24 | US |
4 | 24 | GB |
My current query looks like this:
CREATE TABLE #tmpTarget (TargetId INT, CountryId VARCHAR(100));
INSERT INTO [MySchema].[Target]([IsPrivate], [IsPublic])
OUTPUT inserted.TargetId, CountryId INTO #tmpTarget
SELECT IsPrivate, IsPublic
FROM #TARGETS
Of course this query doesn't work. I'm currently thinking of how to solve this issue. Do you have some ideas or useful tips for me on how to solve this problem?
Thanks a lot! :)
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.