How to crossreference and combine values from many tables - sql

I have three tables, tblTemplates, tblBLNALM and tblPrefs. They follow this structure:
tblPrefs:
--------------------------------------------
| Pref | Derived-Template | Template |
--------------------------------------------
|GA |BLNALM_F03 |AIN_F03 |
--------------------------------------------
|HSSD |BLNALM_F01 |AIN_F01 |
-------------------------------------------- etc...
tblBLNALM:
------------------------------------------------------------------
| Controller | Compound | Tagname | BaseTemplate | Name |
------------------------------------------------------------------
|15CP42 |15F00 |HSSD30001C |BLNALM |IN_7 |
------------------------------------------------------------------
|15CP12 |15F06 |GA123456 |BLNALM |IN_3 |
------------------------------------------------------------------ etc...
tblTemplates:
---------------------------------------
| Template | Maintenance Override |
---------------------------------------
|AIN_F01 |IN_7 |
---------------------------------------
|AIN_F02 |IN_5 |
---------------------------------------
|AIN_F03 |IN_7 |
---------------------------------------etc...
What I need to do is to look if the characters before the numbers start in tblBLNALM.Tagname exist in tblPrefs, if they do, use this to determine what template it is. Then using this template and tblTemplates work out what Maintenance override it is.
The end result should look kind of like this:
-----------------------------------------------------------------------------
| Controller | Compound | Tagname | Template | Maintenance Override |
-----------------------------------------------------------------------------
|15CP12 |15F06 |GA123456 |AIN_F03 |IN_7 |
----------------------------------------------------------------------------- etc...
My gut instinct was to use a few EXISTS statements and maybe nest them, but this hasn't helped, so where do I go from here?
I'm using msaccess 2010.

You can use string operations within SQL joins.
how about comparing if the tagname begins with your pref?
in SQL that would be:
SELECT tblBLNALM.Controller,
tblBLNALM.Compound,
tblBLNALM.Tagname,
tblTemplates.Template,
tblTemplates.[Maintenance Override]
FROM (tblTemplates
INNER JOIN tblPrefs ON tblTemplates.Template = tblPrefs.Template)
INNER JOIN tblBLNALM ON (tblPrefs.Pref = left(tblBLNALM.Tagname, len(tblPrefs.Pref)));
output will be as you described:
+------------+----------+------------+----------+----------------------+
| Controller | Compound | Tagname | Template | Maintenance Override |
+------------+----------+------------+----------+----------------------+
| 15CP12 | 15F06 | GA123456 | AIN_F03 | IN_7 |
| 15CP42 | 15F00 | HSSD30001C | AIN_F01 | IN_7 |
+------------+----------+------------+----------+----------------------+

Join 3 tables: join Template fields in tblPrefs and tblTemplates, then you should join Tagname of tblBLNALM and Pref, but here you cannot join fields directly, so create a query, where select all columns from tblBLNALM and add a calculated column, which returns starting letters from Tagname field and use it in join with tblPrefs instead of table.

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 to use JOIN, CROSS JOIN to combine globalized stored values in SQL into a single table

We have various tables pertaining to different entities where we would like to globalize the stored values. We do not know how to proceed technically anymore and are open to any form of help, hints or tips.
Language
ID | Culture | Description |
---+---------+-------------+
1 | EN | English |
2 | FR | French |
3 | ES | Spanish |
Job
ID | Description |
---+-------------+
1 | Doctor |
2 | Firefighter |
JobGlobalization
ID | JobID | Description | Culture |
---+-------+-------------+---------+
1 | 1 | Docteur | FR |
2 | 1 | Doctora | ES |
We attempted to use CROSS JOIN to obtain something of the following:
ID | Description | Culture |
---+-------------+---------+
1 | Doctor | EN |
1 | Doctor | FR |
1 | Doctor | ES |
2 | Firefighter | ES |
2 | Firefighter | ES |
2 | Firefighter | ES |
Query used:
SELECT Job.ID, Job.Description, Language.Culture
CROSS JOIN Language
ORDER BY Job.ID
We experienced with different joins on the child globalization table in order to correlate the entities together, however the results set kept multiplying itself in the wrong way.
We would like that for every parent entity, whether it has any related child entities, a row is selected for every culture in the Language table. The description column will default to the parent entity in the case where there are no associated records in the child table.
The resulting table should be as follows:
ID | Description | Culture |
---+-------------+---------+
1 | Doctor | EN |
1 | Docteur | FR |
1 | Doctora | ES |
2 | Firefighter | EN |
2 | Firefighter | FR |
2 | Firefighter | ES |
We had in mind a condition that would select the 'Description' column from the parent table 'Job' if there were no corresponding record for it in the child table.
e.g.
IIF(JobGlobalization.Description IS NOT NULL, JobGlobalization.Description, Job.Description)
We attempted to use CROSS JOIN to obtain something of the following:
This should produce the result set you describe:
SELECT j.ID, j.Description, l.Culture
FROM Job j CROSS JOIN
Language l
ORDER BY j.ID, l.Culture;
You can insert this into JobGlobalization (although you might want to truncate it first). Or you can use CREATE TABLE AS (or the equivalent for your database) to create JobGlobalization from scratch.
You would then need to update this table with the appropriate values for the culture.

Filling information from same and other tables in SQL

For my further work I need to create a lookup table where all the different IDs my data has (because of different sources) are noted.
It has to look like this:
Lookup_Table:
| Name | ID_source1 | ID_source2 | ID_source3 |
-----------------------------------------------
| John | EMP_992 | AKK81239K | inv1000003 |
Note, that Name and ID_Source1 are coming from the same table. The other IDs are coming from different tables. They share the same name value, so e.g. source 2 looks like this:
Source2 Table:
| Name | ID |
--------------------
| John | AKK81239K |
What is the SQL code to accomplish this? Im using Access and it doesnt seem to work with this code for source 2:
INSERT INTO Lookup_Table ([ID_Source2])
SELECT [Source2].[ID]
FROM Lookup_Table LEFT JOIN [Source2]
ON [Lookup_Table].[Name] = [Source2].[Name]
It just adds the ID from Source2 in a new row:
| Name | ID_source1 | ID_source2 | ID_source3 |
-----------------------------------------------
| John | EMP_992 | | |
| | | AKK81239K | |
Hope you guys can help me.
You're looking for an UPDATE query, not an INSERT query.
An UPDATE query updates existing records. An INSERT query inserts new records into a table.
UPDATE Lookup_Table
INNER JOIN [Source2] ON [Lookup_Table].[Name] = [Source2].[Name]
SET [ID_Source2] = [Source2].[ID]

Unique string table in SQL and replacing index values with string values during query

I'm working on an old SQL Server database that has several tables that look like the following:
|-------------|-----------|-------|------------|------------|-----|
| MachineName | AlarmName | Event | AlarmValue | SampleTime | ... |
|-------------|-----------|-------|------------|------------|-----|
| 3 | 180 | 8 | 6.780 | 2014-02-24 | |
| 9 | 67 | 8 | 1.45 | 2014-02-25 | |
| ... | | | | | |
|-------------|-----------|-------|------------|------------|-----|
There is a separate table in the database that only contains unique strings, as well as the index for each unique string. The unique string table looks like this:
|----------|--------------------------------|
| Id | String |
|----------|--------------------------------|
| 3 | MyMachine |
| ... | |
| 8 | High CPU Usage |
| ... | |
| 67 | 404 Error |
| ... | |
|----------|--------------------------------|
Thus, when we want to get something out of the database, we get the respective rows out, then lookup each missing string based on the index value.
What I'm hoping to do is to replace all of the string indexes with the actual values in a single query without having to do post-processing on the query result.
However, I can't figure out how to do this in a single query. Do I need to use multiple JOINs? I've only been able to figure out how to replace a single value by doing something like -
SELECT UniqueString.String AS "MachineName" FROM UniqueString
JOIN Alarm ON Alarm.MachineName = UniqueString.Id
Any help would be much appreciated!
Yes, you can do multiple joins to the UniqueStrings table, but change the order to start with the table you are reporting on and use unique aliases for the joined table. Something like:
SELECT MN.String AS 'MachineName', AN.String as 'AlarmName' FROM Alarm A
JOIN UniqueString MN ON A.MachineName = MN.Id
JOIN UniqueString AN ON A.AlarmName = AN.Id
etc for any other columns

Grouped string aggregation / LISTAGG for SQL Server

I'm sure this has been asked but I can't quite find the right search terms.
Given a schema like this:
| CarMakeID | CarMake
------------------------
| 1 | SuperCars
| 2 | MehCars
| CarMakeID | CarModelID | CarModel
-----------------------------------------
| 1 | 1 | Zoom
| 2 | 1 | Wow
| 3 | 1 | Awesome
| 4 | 2 | Mediocrity
| 5 | 2 | YoureSettling
I want to produce a dataset like this:
| CarMakeID | CarMake | CarModels
---------------------------------------------
| 1 | SuperCars | Zoom, Wow, Awesome
| 2 | MehCars | Mediocrity, YoureSettling
What do I do in place of 'AGG' for strings in SQL Server in the following style query?
SELECT *,
(SELECT AGG(CarModel)
FROM CarModels model
WHERE model.CarMakeID = make.CarMakeID
GROUP BY make.CarMakeID) as CarMakes
FROM CarMakes make
http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
It is an interesting problem in Transact SQL, for which there are a number of solutions and considerable debate. How do you go about producing a summary result in which a distinguishing column from each row in each particular category is listed in a 'aggregate' column? A simple, and intuitive way of displaying data is surprisingly difficult to achieve. Anith Sen gives a summary of different ways, and offers words of caution over the one you choose...
If it is SQL Server 2017 or SQL Server VNext, Azure SQL database you can use String_agg as below:
SELECT make.CarMakeId, make.CarMake,
CarModels = string_agg(model.CarModel, ', ')
FROM CarModels model
INNER JOIN CarMakes make
ON model.CarMakeId = make.CarMakeId
GROUP BY make.CarMakeId, make.CarMake
Output:
+-----------+-----------+---------------------------+
| CarMakeId | CarMake | CarModels |
+-----------+-----------+---------------------------+
| 1 | SuperCars | Zoom, Wow, Awesome |
| 2 | MehCars | Mediocrity, YoureSettling |
+-----------+-----------+---------------------------+