SQL aggregate values and add new columns - sql

I am having some trouble to aggregate data on row-inputs. I have two columns originally, but i want to split the data based on PortID and add five columns which now lie in the AssetClass column as row values.
The first table is how the data is structured now, the second is what i want it to look like.
Anyone have any tips how to do this? Thanks in advance.

You basically need to pivot your data set. Below query will pivot you data set purely using UNION and GROUP BY Clause which will be supported by any database system. You can add your pivot asset class S,U,P inside set_union block as done for C,F
Alternatively, you can simply use PIVOT operator.
CREATE TABLE sample
(
id int,
port_id nvarchar(10),
percent_weight int,
asset_class nvarchar(1)
);
INSERT INTO sample values
('1','SOL','15','C'),
('2','EID','20','C'),
('3','PAR','25','C'),
('45','SOL','30','F'),
('46','EID','40','F'),
('47','PAR','45','F')
;
SELECT
port_id,
MAX(C) AS C,
MAX(F) AS F
FROM
(
SELECT
id,
port_id,
percent_weight AS C,
NULL AS F
FROM
sample
WHERE
asset_class='C'
UNION
SELECT
id,
port_id,
NULL AS C,
percent_weight AS F
FROM
sample
WHERE
asset_class='F'
)set_union
GROUP BY
port_id
ORDER BY
id ASC;
Output:

Related

QUERY which allows me to ungroup a column with multiple values

I need your support to put together a query that allows me to ungroup a column with multiple values in a single line in this case the column CONDICIONES:
I have the CONDICIONES table with the columns Hora TRX; Fecha TRX; Condiciones; Código Cliente.
In my Teradata query, I am making it look for the conditions:
WHERE CONDICIONES LIKE ANY ('%0800%', '%0801%', '%0805%', '%0806%', '%0821%'|;
but the ungrouped information does not throw me away.
What I need is the query to return the following result:
Desired output:
Table:
The easiest way is probably to split all values into rows before filtering/aggregationg:
WITH cte AS
( -- prepare the data
SELECT "Fecha TRX" AS pk, CONDICIONES AS delim_str
FROM vt
)
SELECT "Fecha TRX", CONDICIONES, Count(*)
FROM TABLE (StrTok_Split_To_Table(cte.pk, cte.delim_str, '?')
RETURNS ("Fecha TRX" VARCHAR(20) -- should be the same datatype as input "Fecha TRX"
,tokennum INTEGER
,CONDICIONES VARCHAR(10) )
) AS dt
WHERE CONDICIONES IN ('0800', '0801', '0805', '0806', '0821');
GROUP BY 1,2;

Selecting most recent timestamp row and getting values from a column with a Variant DataType

I hope the title makes some sense, I'm open to suggestions if I should make it more readable.
I have a temp table in Snowflake called BI_Table_Temp. It has 2 columns Load_DateTime with a datatype Timestamp_LTZ(9) and JSON_DATA which is a Variant datatype that's has nested records from a JSON file. I want to query this table which I then plan to ingest to another table but I want to make sure I always get the most recent Load_DateTime row.
I've tried this, which works but it shows me the Load_DateTime column and I don't want that I just want to get the values from the JSON_DATA row that has the max Load_DateTime timestamp:
SELECT
MAX(Load_DateTime),
transactions.value:id::string as id
transactions.value:value2::string as account_value
transactions.value:value3::string as new_account_value
FROM BI_Table_Temp,
LATERAL FLATTEN (JSON_DATA:transactions) as transactions
GROUP BY transactions.value
A simple option:
WITH data AS (
SELECT Load_DateTime
, transactions.value:id::string as id
, transactions.value:value2::string as account_value
, transactions.value:value3::string as new_account_value
FROM BI_Table_Temp,
LATERAL FLATTEN (JSON_DATA:transactions) as transactions
), max_load AS (
SELECT MAX(Load_DateTime) Load_DateTime, id
FROM data,
GROUP BY id
)
SELECT transactions.value:id::string as id
, transactions.value:value2::string as account_value
, transactions.value:value3::string as new_account_value
FROM data
JOIN max_load
USING (id, Load_DateTime)
Since transactions.value is a variant, I'm guessing that for GROUP BY transactions.value you really mean GROUP BY transactions.value:id.

I need to SELECT a group of columns not null

Basically, i have a table that have a series of columns named:
ATTRIBUTE10, ATTRIBUTE11, ATTRIBUTE12 ... ATTRIBUTE50
I want a query that gives me all the columns from ATTRIBUTE10 to ATTRIBUTE50 not null
As others have commented we aren't exactly sure of your requirements, but if you want a list the UNPIVOT can do that...
SELECT attribute , value
FROM
(SELECT * from YourFile) p
UNPIVOT
(value FOR attribute IN
(attribute1, attribute2, attribute3, etc.)
)AS unpvt
May be you can use where condition for all columns Or use between operator as below.
For All Columns
where ATTRIBUTE10 is not null and ATTRIBUTE11 is not null ...... and ATTRIBUTE50 is not null
By using between operator
where ATTRIBUTE10 between ATTRIBUTE11 and ATTRIBUTE50
One way to approach the problem is to unfold your table-with-a-zillion-like-named-attributes into one in which you've got one attribute per row, with appropriate foreign keys back to the original table. So something like:
CREATE TABLE ATTR_TABLE AS
SELECT ID_ATTR, ID_TABLE_WITH_ATTRS, ATTR
FROM (SELECT ((ID_TABLE_WITH_ATTRS-1)*100)+1 AS ID_ATTR, ID_TABLE_WITH_ATTRS, ATTRIBUTE10 AS ATTR FROM TABLE_WITH_ATTRS UNION ALL
SELECT ((ID_TABLE_WITH_ATTRS-1)*100)+2, ID_TABLE_WITH_ATTRS, ATTRIBUTE11 FROM TABLE_WITH_ATTRS UNION ALL
SELECT ((ID_TABLE_WITH_ATTRS-1)*100)+3, ID_TABLE_WITH_ATTRS, ATTRIBUTE12 FROM TABLE_WITH_ATTRS);
This only unfolds ATTRIBUTE10, ATTRIBUTE11, and ATTRIBUTE12, but you should be able to get the idea - the rest of the attributes just requires a little cut-n-paste on your part.
You can then query this table to find your non-NULL attributes as
SELECT *
FROM ATTR_TABLE
WHERE ATTR IS NOT NULL
ORDER BY ID_ATTR
Hopefully the difficulty you're encountering in dealing with this table-with-a-zillion-repeated-fields teaches you a hard lesson about exactly why tables with repeated fields or groups of fields are a Bad Idea.
dbfiddle here

SQL: How to dynamically loop & add N number of column with NULL value into temp table

Due to a certain requirement, I need to create two temp tables in Stored Procedure, after processing some data into them, I need to combine the two temp tables to show as one result set and generate into excel. So I'm thinking to use UNION when I want to show the final result set.
The issue is, the first temp table (Table A) is fixed to 20 columns, and the second temp table has 50 columns (Table B). My plan is, before processing data for Table A, I want to add 30 nullable columns and insert data for first 20 columns, and the rest is all NULL
After I process the data for Table B, I use UNION to combine Table A & B so that they will show as one result set.
What I can think of right now is to hard code some columns that are destined to have null values when I declare the temp table:
Declare #tmpTableA table (
....
ProcessDate datetime,
Mode int,
Col21 varchar(10)
Col22 varchar(10)
....
Col50 varchar(50)
)
When I insert data into Table A, I have to manually add null from Col21 onwards
Insert into(.... Col21, Col22, Col23....)
Values (.... NULL, NULL, NULL....)
After I complete processing data for Table A & B, I use UNION to merge Table A and B
Select *....Col49,Col50 From Table A
Union
Select *....CompleteDate,ContactPerson From Table B
Instead of hard-coding Col21 to Col50 into Table A, is there any elegant way to achieve that like using while loop to dynamically add N number of columns into Table A?
EDIT:
According to latest requirement, Table B has not only 50 columns but 100 columns! I really need a way to dynamically loop those columns rather than hard-coding for over 80 columns
I think you can just do
select * into #tableA from #tableB where 1=2
with this both tables will have same columns
You don't need to add columns to table A, just add 30 NULLs to select from Table A.
Select *,NULL,...,NULL,NULL From Table A
Union
Select * From Table B
You could add aliases to make the result a bit cleaner
Select *,...,NULL CompleteDate, NULL ContactPerson From Table A
Union
Select * From Table B

How to combine three tables into a new table

all with the same column headings and I would like to create one singular table from all three.
I'd also, if it is at all possible, like to create a trigger so that when one of these three source tables is edited, the change is copied into the new combined table.
I would normally do this as a view, however due to constraints on the STSrid, I need to create a table, not a view.
Edit* Right, this is a bit ridiculous but anyhow.
I HAVE THREE TABLES
THERE ARE NO DUPLICATES IN ANY OF THE THREE TABLES
I WANT TO COMBINE THE THREE TABLES INTO ONE TABLE
CAN SOMEONE HELP PROVIDE THE SAMPLE SQL CODE TO DO THIS
ALSO IS IT POSSIBLE TO CREATE TRIGGERS SO THAT WHEN ONE OF THE THREE TABLES IS EDITED THE CHANGE IS PASSED TO THE COMBINED TABLE
I CAN NOT CREATE A VIEW DUE TO THE FACT THAT THE COMBINED TABLE NEEDS TO HAVE A DIFFERENT STSrid TO THE SOURCE TABLES, CREATING A VIEW DOES NOT ALLOW ME TO DO THIS, NOR DOES AN INDEXED VIEW.
Edit* I Have Table A,Table B and Table C all with columns ORN, Geometry and APP_NUMBER. All the information is different so
Table A (I'm not going to give an example geometry column)
ORN ID
123 14/0045/F
124 12/0002/X
Table B (I'm not going to give an example geometry column)
ORN ID
256 05/0005/D
989 12/0012/X
Table C (I'm not going to give an example geometry column)
ORN ID
043 13/0045/D
222 11/0002/A
I want one complete table of all info
Table D
ORN ID
123 14/0045/F
124 12/0002/X
256 05/0005/D
989 12/0012/X
043 13/0045/D
222 11/0002/A
Any help would be greatly appreciated.
Thanks
If the creation of the table is a one time thing you can use a select into combined with a union like this:
select * into TableD from
(
select * from TableA
union all
select * from TableB
union all
select * from TableC
) UnionedTables
As for the trigger, it should be easy to set up a after insert trigger like this:
CREATE TRIGGER insert_trigger
ON TableA
AFTER INSERT AS
insert TableD (columns...) select (columns...) from inserted
Obviously you will have to change the columns... to match your structure.
I haven't checked the syntax though so it might not be prefect and it could need some adjustment, but it should give you an idea I hope.
If IDs are not duplicated it ill be easy to achieve it, in another case you can must add a OriginatedFrom column. You also can create a lot of instead off triggers (not only for insert but for delete and update) but that a lazy excuse for not refactoring the app.
Also you must pay attention for any reference for the data, since its a RELATIONAL model is likely to other tables are related to the table you are about to drop.
This is the code for create the table D
drop table D;
Select * into D from (select * from A Union all select* from B Union all select * from C);
Its rather simple Just Create Table_D First
CREATE TABLE_D
(
ORN INT,
ID VARCHAR(20),
Column3 Datatype
)
GO
Use INSERT statement to insert records into this table SELECTing and using UNION ALL operator from other three table.
INSERT INTO TABLE_D (ORN , ID, Column3)
SELECT ORN , ID, Column3
FROM Table_A
UNION ALL
SELECT ORN , ID, Column3
FROM Table_B
UNION ALL
SELECT ORN , ID, Column3
FROM Table_C
Trigger
You will need to create this trigger on all of the tables.
CREATE TRIGGER tr_Insert_Table_A
ON TABLE_A
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO TABLE_D (ORN , ID, Column3)
SELECT i.ORN , i.ID, i.Column3
FROM Inserted i LEFT JOIN TABLE_D D
ON i.ORN = D.ORN
WHERE D.ORN IS NULL
END
Read here to learn more about SQL Server Triggers