Multiple Self-Join based on GROUP BY results - sql

I'm attempting to collect details about backup activity from a ProgreSQL DB table on a backup appliance (Avamar). The table has several columns including: client_name, dataset, plugin_name, type, completed_ts, status_code, bytes_modified and more. Simplified example:
| session_id | client_name | dataset | plugin_name | type | completed_ts | status_code | bytes_modified |
|------------|-------------|---------|---------------------|------------------|----------------------|-------------|----------------|
| 1 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-05T01:00:00Z | 30900 | 11111111 |
| 2 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-04T01:00:00Z | 30000 | 22222222 |
| 3 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-03T01:00:00Z | 30000 | 22222222 |
| 4 | server01 | Windows | Windows File System | Scheduled Backup | 2017-12-02T01:00:00Z | 30000 | 22222222 |
| 5 | server01 | Windows | Windows VSS | Scheduled Backup | 2017-12-01T01:00:00Z | 30000 | 33333333 |
| 6 | server02 | Windows | Windows File System | Scheduled Backup | 2017-12-05T02:00:00Z | 30000 | 44444444 |
| 7 | server02 | Windows | Windows File System | Scheduled Backup | 2017-12-04T02:00:00Z | 30900 | 55555555 |
| 8 | server03 | Windows | Windows File System | On-Demand Backup | 2017-12-05T03:00:00Z | 30000 | 66666666 |
| 9 | server04 | Windows | Windows File System | Validate | 2017-12-05T03:00:00Z | 30000 | 66666666 |
Each client_name (server) can have multiple datasets, and each dataset can have multiple plugin_names. So I have a created a SQL statement that does a GROUP BY of these three columns to get a list of "job" activity over time.
(http://sqlfiddle.com/#!15/f15556/1)
select
client_name,
dataset,
plugin_name
from v_activities_2
where
type like '%Backup%'
group by
client_name, dataset, plugin_name
Each of these Jobs can be successful or fail based on a status_code column. Using self-join with subqueries I'm able to get results of the Last Good backup along with it's completed_ts (completed time) and bytes_modified and more:
(http://sqlfiddle.com/#!15/f15556/16)
select
a2.client_name,
a2.dataset,
a2.plugin_name,
a2.LastGood,
a3.status_code,
a3.bytes_modified as LastGood_bytes
from v_activities_2 a3
join (
select
client_name,
dataset,
plugin_name,
max(completed_ts) as LastGood
from v_activities_2 a2
where
type like '%Backup%'
and status_code in (30000,30005) -- Successful (Good) Status codes
group by
client_name, dataset, plugin_name
) as a2
on a3.client_name = a2.client_name and
a3.dataset = a2.dataset and
a3.plugin_name = a2.plugin_name and
a3.completed_ts = a2.LastGood
I can do the same thing separately to get the Last Attempt details by removing WHERE's status_code line: http://sqlfiddle.com/#!15/f15556/3. Note that most times LastGood and LastAttempted are the same row but sometimes they are not, depending if the last backup was successful.
What I'm having problems with is merging these two statements together (if possible). So I will get this result:
| client_name | dataset | plugin_name | lastgood | lastgood_bytes | lastattempt | lastattempt_bytes |
|-------------|---------|---------------------|----------------------|-----------------|----------------------|-------------------|
| server01 | Windows | Windows File System | 2017-12-04T01:00:00Z | 22222222 | 2017-12-05T01:00:00Z | 11111111 |
| server01 | Windows | Windows VSS | 2017-12-01T01:00:00Z | 33333333 | 2017-12-01T01:00:00Z | 33333333 |
| server02 | Windows | Windows File System | 2017-12-05T02:00:00Z | 44444444 | 2017-12-05T02:00:00Z | 44444444 |
| server03 | Windows | Windows File System | 2017-12-05T03:00:00Z | 66666666 | 2017-12-05T03:00:00Z | 66666666 |
I attempted just adding another RIGHT JOIN to the end (http://sqlfiddle.com/#!15/f15556/4) and getting NULL rows. After doing some reading I see that the first two JOINs run first creating a temporary table before the 2nd join occurs, but at that point the data I need is lost so I get NULL rows.
Using PostgreSQL 8 via groovy scripting. I also only have read-only access to the DB.

You apparently have two intermediate inner join output tables and you want to get columns from each about some things identified by a common key. So inner join them on the key.
select
g.client_name,
g.dataset,
g.plugin_name,
LastGood,
g.status_code,
LastGood_bytes
LastAttempt,
l.status_code,
LastAttempt_bytes
from
( -- cut & pasted Last Good http://sqlfiddle.com/#!15/f15556/16
select
a2.client_name,
a2.dataset,
a2.plugin_name,
a2.LastGood,
a3.status_code,
a3.bytes_modified as LastGood_bytes
from v_activities_2 a3
join (
select
client_name,
dataset,
plugin_name,
max(completed_ts) as LastGood
from v_activities_2 a2
where
type like '%Backup%'
and status_code in (30000,30005) -- Successful (Good) Status codes
group by
client_name, dataset, plugin_name
) as a2
on a3.client_name = a2.client_name and
a3.dataset = a2.dataset and
a3.plugin_name = a2.plugin_name and
a3.completed_ts = a2.LastGood
) as g
join
( -- cut & pasted Last Attempt http://sqlfiddle.com/#!15/f15556/3
select
a1.client_name,
a1.dataset,
a1.plugin_name,
a1.LastAttempt,
a3.status_code,
a3.bytes_modified as LastAttempt_bytes
from v_activities_2 a3
join (
select
client_name,
dataset,
plugin_name,
max(completed_ts) as LastAttempt
from v_activities_2 a2
where
type like '%Backup%'
group by
client_name, dataset, plugin_name
) as a1
on a3.client_name = a1.client_name and
a3.dataset = a1.dataset and
a3.plugin_name = a1.plugin_name and
a3.completed_ts = a1.LastAttempt
) as l
on l.client_name = g.client_name and
l.dataset = g.dataset and
l.plugin_name = g.plugin_name
order by client_name, dataset, plugin_name
This uses one of the applicable approaches in Strange duplicate behavior from GROUP_CONCAT of two LEFT JOINs of GROUP_BYs. However the correspondence of chunks of code might not be so clear. Its intermediate are left vs your inner & group_concat is your max. (But it has more approaches because of particulars of group_concat & its query.)
A correct symmetrical INNER JOIN approach: LEFT JOIN q1 & q2--1:many--then GROUP BY & GROUP_CONCAT (which is what your first query did); then separately similarly LEFT JOIN q1 & q3--1:many--then GROUP BY & GROUP_CONCAT; then INNER JOIN the two results ON user_id--1:1.
A correct cumulative LEFT JOIN approach: JOIN q1 & q2--1:many--then GROUP BY & GROUP_CONCAT; then left join that & q3--1:many--then GROUP BY & GROUP_CONCAT.
Whether this actually serves your purpose in general depends on your actual specification and constraints. Even if the two joins you link are what you want you need to explain exactly what you mean by "merge". You don't say what you want if the joins have different sets of values for the grouped columns. Force yourself to use the English language to say what rows go in the result based on what rows are in the input.
PS 1 You have undocumented/undeclared/unenforced constraints. Please declare when possible. Otherwise enforce by triggers. Document in question text if not in code. Constraints are fundamental to multiple subrow value instances in join & to group by.
PS 2 Learn the syntax/semantics for select. Learn what left/right outer join ons return--whatinner join on does plus unmatched left/right table rows extended by nulls.
PS 3 Is there any rule of thumb to construct SQL query from a human-readable description?

Here is an alternate way that also works but harder to follow and likely more particular to my dataset: http://sqlfiddle.com/#!15/f15556/114
select
Actvty.client_name,
Actvty.dataset,
Actvty.plugin_name,
ActvtyGood.LastGood,
ActvtyGood.status_code as LastGood_status,
ActvtyGood.bytes_modified as LastGood_bytes,
ActvtyOnly.LastAttempt,
Actvty.status_code as LastAttempt_status,
Actvty.bytes_modified as LastAttempt_bytes
from v_activities_2 Actvty
-- 1. Get last attempt of each job (which may or may not match last good)
join (
select
client_name,
dataset,
plugin_name,
max(completed_ts) as LastAttempt
from v_activities_2
where
type like '%Backup%'
group by
client_name, dataset, plugin_name
) as ActvtyOnly
on Actvty.client_name = ActvtyOnly.client_name and
Actvty.dataset = ActvtyOnly.dataset and
Actvty.plugin_name = ActvtyOnly.plugin_name and
Actvty.completed_ts = ActvtyOnly.LastAttempt
-- 4. join the list of good runs with the table of last attempts, there would never be a job that has a last good without also a last attempt.
join (
-- 3. join last good runs with the full table to get the additional details of each
select
ActvtyGoodSub.client_name,
ActvtyGoodSub.dataset,
ActvtyGoodSub.plugin_name,
ActvtyGoodSub.LastGood,
ActvtyAll.status_code,
ActvtyAll.bytes_modified
from v_activities_2 ActvtyAll
-- 2. Get last Good run of each job
join (
select
client_name,
dataset,
plugin_name,
max(completed_ts) as LastGood
from v_activities_2
where
type like '%Backup%'
and status_code in (30000,30005) -- Successful (Good) Status codes
group by
client_name, dataset, plugin_name
) as ActvtyGoodSub
on ActvtyAll.client_name = ActvtyGoodSub.client_name and
ActvtyAll.dataset = ActvtyGoodSub.dataset and
ActvtyAll.plugin_name = ActvtyGoodSub.plugin_name and
ActvtyAll.completed_ts = ActvtyGoodSub.LastGood
) as ActvtyGood
on Actvty.client_name = ActvtyGood.client_name and
Actvty.dataset = ActvtyGood.dataset and
Actvty.plugin_name = ActvtyGood.plugin_name

Related

MS Access 2016 - Pull client name from separate table in complex query

I have three tables for vulnerability scanning jobs: customers, authorization forms, and scans. Relationships are one to many from left to right. I previously had scans directly related to clients, but implemented the forms table to add the ability to prevent scanning without authorization. I have the below query which pulls the dates of the most recent and next coming scans (huge thanks to #donPablo), but when I made the change in tables I'm no longer pulling the correct data from the customers table. I'm not exactly sure how to fix it.
SELECT u.Customer_Company, z.*
FROM (Select
NZ(a.Scan_Data.Customer_ID, b.Scan_Data.Customer_ID) as Customer,
aPast as Past,
aFuture as Future,
DATEDIFF("d", aPast, aFuture) as Difference
FROM
(Select Scan_Data.Customer_ID, Max(Scan_Date) as aPast from Scan_Data where Scan_Date <= DATE() Group By Scan_Data.Customer_ID) a
LEFT JOIN
(Select Scan_Data.Customer_ID, Min(Scan_Date) as aFuture from Scan_Data where Scan_Date > DATE() Group By Scan_Data.Customer_ID) b
ON a.Scan_Data.Customer_ID = B.Scan_Data.Customer_ID
UNION
Select
NZ(a.Scan_Data.Customer_ID, b.Scan_Data.Customer_ID) as Customer,
aPast as Past,
aFuture as Future,
DATEDIFF("d", aPast, aFuture) as Difference
FROM
(Select Scan_Data.Customer_ID, Max(Scan_Date) as aPast from Scan_Data where Scan_Date <= DATE() Group By Scan_Data.Customer_ID) a
RIGHT JOIN
(Select Scan_Data.Customer_ID, Min(Scan_Date) as aFuture from Scan_Data where Scan_Date > DATE() Group By Scan_Data.Customer_ID) b
ON a.Scan_Data.Customer_ID = B.Scan_Data.Customer_ID
) AS z LEFT JOIN Customer_Data AS u ON cint(z.Customer) = cint(u.Customer_ID);
In this query the Scan_Data.Customer_ID winds up being the FormID and it then pulls the customer's name based on the FormID. I fixed it in my other queries by doing a double inner join to pull the actual CustomerID based on the FormID, but I can't get that to work here because of the existing joins. Form_Data.Customer_ID is the way it's identified in the Form table. All IDs in their primary tables are autonumber generated PKs.
Customer_Data table:
.Customer_ID | .Customer_Name | etc.
1 | Microsoft |
2 | Reddit |
Form_Data table:
.Form_ID | .Signature_Date | .Expiration_Date | .Customer_ID
1 | 01-Jan-19 | 01-Jan-20 | 2/Reddit
2 | 15-May-18 | 15-May-21 | 1/Microsoft
Scan_Data table:
.Scan_ID | .Scan_Title | .Scan_Date | .Customer_ID
1 | First MS 19052018 | 19-May-18 | 1/2/Reddit
2 | First R 05012019 | 05-Jan-19 | 2/1/Microsoft
The above Scan_Data shows the problem I'm having. The numbers in the Scan_Data.Customer_ID field are the PKs from the other two tables. The .Customer_ID field is pulling the customer ID based upon the form ID and not the actual customer ID. It should show like this:
.Scan_ID | .Scan_Title | .Scan_Date | .Customer_ID
1 | First MS 19052018 | 19-May-18 | 2/1/Microsoft
2 | First R 05012019 | 05-Jan-19 | 1/2/Reddit

How to return a single value built from values stored in multiple records?

I am an application developer unfortunately put in the position of needing to write (/update) the SQL statement in order to return data for the application. My experience with SQL is limited, so would appreciate any help.
We have a Oracle Database 11g (11.2.0.4.0)
Example Tables
I've created the following example which replicates our set-up. It consists of:
A main table which contains records of trips around different cities. (MAIN_TRIP_TABLE)
Various additional tables which contain additional properties linked to these trips via INNER JOINs. (ADDITIONAL_TABLE)
A separate table showing the steps taken along the journey (ie. interim locations visited). A value of STEP_NUM = 1 is always the final destination, and thus there is always at least 1 record in this table per trip in the main table. If there were any interim stops made of the journey they are listed in this table as separate records with STEP_NUM iterating upwards. (JOURNEY_STEPS_TABLE)
MAIN_TRIP_TABLE
RECORD_ID | PROP_1 | PROP_2 | FINAL_DEST | ...
-------------------------------------------------
10001 | A | 1 | London | ...
10002 | A | 0 | Reading | ...
10003 | B | 1 | Leeds | ...
10004 | B | 0 | York | ...
ADDITIONAL_TABLE
RECORD_ID | PROP_3 | ...
------------------------
10001 | X | ...
10002 | Y | ...
10003 | Y | ...
10004 | X | ...
JOURNEY_STEPS_TABLE
RECORD_ID | STEP_NUM | LOCATION | ...
--------------------------------------
10001 | 1 | London | ...
10002 | 1 | Reading | ...
10002 | 2 | Bath | ...
10003 | 1 | Leeds | ...
10003 | 2 | York | ...
10003 | 3 | Bristol | ...
10004 | 1 | York | ...
10004 | 2 | Cardiff | ...
10004 | 3 | Oxford | ...
10004 | 4 | London | ...
Issue
I want to retrieve something that looks like:
SELECT
MAIN_TRIP_TABLE.RECORD_ID
, MAIN_TRIP_TABLE.PROP_1
, MAIN_TRIP_TABLE.PROP_2
, ADDITIONAL_TABLE.PROP_3
, <Concatenation/Array of JOURNEY_STEPS_TABLE> as "InterimStops"
FROM MAIN_TRIP_TABLE
INNER JOIN ADDITIONAL_TABLE ON MAIN_TRIP_TABLE.RECORD_ID = ADDITIONAL_TABLE.RECORD_ID
LEFT OUTER JOIN JOURNEY_STEPS_TABLE ON MAIN_TRIP_TABLE.RECORD_ID = JOURNEY_STEPS_TABLE.RECORD_ID
Where the "InterimStops" value above is some sort of concatenation of any and all values in found in the JOURNEY_STEPS_TABLE, for that particular RECORD_ID, in order of increasing STEP_NUM, with some sort of deliminator. (eg for '10001' I would want just "London", and for '10004' I would want "York,Cardiff,Oxford,London").
If I get something like this, I can then separate these out to an JSON array, within the application I'm developing.
Note: The actual SQL SELECT query is already significantly more complex with other fields and tables, so changing the query away from 1 SELECT query (ie. instead using multiple queries), is something I'd like to avoid unless absolutely necessary.
Things I've tried
After some Googling, I started to build a SQL statement using LISTAGG, and to begin with it looked promising:
SELECT
MAIN_TRIP_TABLE.RECORD_ID
, LISTAGG(JOURNEY_STEPS_TABLE.LOCATION, ',') WITHIN GROUP (ORDER BY JOURNEY_STEPS_TABLE.STEP_NUMBER) "InterimStops"
FROM MAIN_TRIP_TABLE
LEFT OUTER JOIN JOURNEY_STEPS_TABLE ON MAIN_TRIP_TABLE.RECORD_ID = JOURNEY_STEPS_TABLE.RECORD_ID
GROUP BY MAIN_TRIP_TABLE.RECORD_ID
This returned exactly the sort of value I was looking for, but this failed as soon as I tried to bring back in the other values from both the main table and additional tables (eg: MAIN_TRIP_TABLE.PROP_1, MAIN_TRIP_TABLE.PROP_2, ADDITIONAL_TABLE.PROP_3). This gave me a "ORA-00979: not a GROUP BY expression" error.
I then tried to get this data via a subquery but struggled to get anything working.
Any help, insight, or pointing in the right direct, would be very much appreciated.
Many Thanks
It's easier to do this with a subquery so you don't have to group the data on the joined set of columns (as you allready tried):
SELECT MAIN_TRIP_TABLE.RECORD_ID
, (SELECT LISTAGG(JOURNEY_STEPS_TABLE.LOCATION, ',') WITHIN GROUP (ORDER BY JOURNEY_STEPS_TABLE.STEP_NUMBER)
FROM JOURNEY_STEPS_TABLE
WHERE JOURNEY_STEPS_TABLE.RECORD_ID = MAIN_TRIP_TABLE.RECORD_ID) "InterimStops"
FROM MAIN_TRIP_TABLE
The other possibility is to LEFT JOIN the grouped data:
SELECT MAIN_TRIP_TABLE.RECORD_ID
, JOURNEY_STEPS_TABLE."InterimStops"
FROM MAIN_TRIP_TABLE
LEFT JOIN (SELECT RECORD_ID
, LISTAGG(LOCATION, ',') WITHIN GROUP (ORDER BY STEP_NUMBER) "InterimStops"
FROM JOURNEY_STEPS_TABLE
GROUP BY RECORD_ID) JOURNEY_STEPS_TABLE
ON JOURNEY_STEPS_TABLE.RECORD_ID = MAIN_TRIP_TABLE.RECORD_ID

SQL structure for multiple queries of the same table (using window function, case, join)

I have a complex production SQL question. It's actually PrestoDB Hadoop, but conforms to common SQL.
I've got to get a bunch of metrics from a table, a little like this (sorry if the tables are mangled):
+--------+--------------+------------------+
| device | install_date | customer_account |
+--------+--------------+------------------+
| dev 1 | 1-Jun | 123 |
| dev 1 | 4-Jun | 456 |
| dev 1 | 10-Jun | 789 |
| dev 2 | 20-Jun | 50 |
| dev 2 | 25-Jun | 60 |
+--------+--------------+------------------+
I need something like this:
+--------+------------------+-------------------------+
| device | max_install_date | previous_account_number |
+--------+------------------+-------------------------+
| dev 1 | 10-Jun | 456 |
| dev 2 | 25-Jun | 50 |
+--------+------------------+-------------------------+
I can do two separate queries to get max install date and previous account number, like this:
select device, max(install_date) as max_install_date
from (select [a whole bunch of stuff], dense_rank() over(partition by device order by [something_else]) rnk
from some_table a
)
But how do you combine them into one query to get one line for each device? I have rank, with statements, case statements, and one join. They all work individually but I'm banging my head to understand how to combine them all.
I need to understand how to structure big queries.
ps. any good books you recommend on advanced SQL for data analysis? I see a bunch on Amazon but nothing that tells me how to construct big queries like this. I'm not a DBA. I'm a data guy.
Thanks.
You can use correlated subquery approach :
select t.*
from table t
where install_date = (select max(install_date) from table t1 where t1.device = t.device);
This assumes install_date has resonbale date format.
I think you want:
select t.*
from (select t.*, max(install_date) over (partition by device) as max_install_date,
lag(customer_account) over (partition by device order by install-date) as prev_customer_account
from t
) t
where install_date = max_install_date;

JOIN two tables, but only include data from first table in first instance of each unique record

Title might be confusing.
I have a table of Cases, and each Case can contain many Tasks. To achieve a different workflow for each Task, I have different tables such as Case_Emails, Case_Calls, Case_Chats, etc...
I want to build a Query that will eventually be exported to Excel. In this query, I want to list out each Task, and the Tasks are already joined together via a UNION in another table using a common format. For each task in the Query, I want only the first Task associated with a case to include the details from Cases table. Example below:
+----+---------+------------+-------------+-------------+-------------+
| id | Case ID | Agent Name | Task Info 1 | Task Info 2 | Task Info 3 |
+----+---------+------------+-------------+-------------+-------------+
| 1 | 4000000 | Some Name | Detailstuff | Stuffdetail | Thingsyo |
| 2 | | | Detailstuff | Stuffdetail | Thingsyo |
| 3 | | | Detailstuff | Stuffdetail | Thingsyo |
| 4 | 4000003 | Some Name | Detailstuff | Stuffdetail | Thingsyo |
| 5 | | | Detailstuff | Stuffdetail | Thingsyo |
| 6 | 4000006 | Some Name | Detailstuff | Stuffdetail | Thingsyo |
+----+---------+------------+-------------+-------------+-------------+
My original approach was attempting a LEFT JOIN on Case ID, but I couldn't figure out how to filter the data out from the extra rows.
This would be much simpler if Access supported the ROW_NUMBER function. It doesn't, but you can sort of simulate it with a correlated subquery using the Tasks table (this assumes that each task has a unique numeric ID). This basically assigns a row number to each task, partitioned by the CaseID. Then you can just conditionally display the CaseID and AgentName where RowNum = 1.
SELECT Switch(RowNum = 1, CaseID) as Case,
Switch(RowNum = 1, AgentName) as Agent,
TaskName
FROM (
SELECT c.CaseID,
c.AgentName,
t.TaskName,
(select count(*)
from Tasks t2
where t2.CaseID = c.CaseID and t2.ID <= t.ID) as RowNum
FROM Cases c
INNER JOIN Tasks t ON c.CaseID = t.CaseID
order by c.CaseID, t.TaskName
)
You didn't post your table structure, so I'm not sure this will work for you as-is, but maybe you can adapt it.
No matter what when you join you will have duplicate values. to remove the duplicates either put in a Distinct in your select or a Group by after your filters. This should resolve the duplicates in you query for task info 1,2,3.
Found out that I can name my tables in the query like so:
FROM Case_Calls Calls
With this other name, I was able to filter based on a sub query:
IIF( Calls.[ID] <> (select top 1 [ID] from Case_Calls where [Case ID] = Calls.[Case ID]), '', Cases.[Creator]) As [Case Creator]
This solution gives me the results that I want :) It's rather ugly SQL, and difficult to parse when I'm dealing with dozens of columns, but it gets the job done!
I'm still curious if there is a better solution...

Joining tables depending on value of cell in another table

I have a database with a few tables of which I am trying to get some data from.
but due to the layout (which I can't do anything about), I can't seem to get a normal JOIN to work.
I have three tables:
datorer
program
volymlicenser
In the table "datorer" is a number of computers (registered with AD name, room number and a cell for comments).
In the table "program" is different programs that my organization have purchased.
In the table "volymlicenser" is the few licenses owned by the organization that is volume licenses.
The cells in here is ID, RegKey and comp_name.
Most programs are OEM licenses and only installed on one computer, hence they never needed to register the program names together with the belonging computer in another table like with the volume licenses.
When the database was designed, it was only containing the two last tables, and no join queries was needed. Recently they added the table "datorer" which consists of the said cells above.
What I would like to do now, is, preferably by one single query, see if the boolean cell program.VL is set to true.
If so, I want to join progran.RegKey on volymlicenser.RegKey, and from there get the contents from volymlicenser.comp_name.
The query I tried with, is the following.. which did not work.
SELECT
prog.Namn AS Program, prog.comp_name AS Datornamn,
pc.room AS Rum, pc.kommentar AS Kommentar
FROM
program AS prog
JOIN
datorer AS pc ON prog.comp_name = pc.comp_name
JOIN
volymlicenser AS vl ON vl.RegKey = prog.RegKey
WHERE
prog.Namn = "Adobe Production Premium CS6"
Hope someone can help me. :)
Please do ask if something is not fully clear!
The following are example records and desired results:
Table datorer:
| id | comp_name | room | kommentar|
|----------------------------------|
| 1 | MB-56C5 | 1.1 | NULL |
| 2 | MB-569B | 4.1 | NULL |
Table program:
| id | Namn | amount | VL | RegKey | comp_name | leveranotor | purchased | note | Suite | SuiteContents |
|-----------------------------------------------------------------------------------------------|
| 1 | Adobe Production Premium CS6 | 2 | 1 | THE-ADOBE-SERIAL | NULL | Atea | 2012-11-01 | Purchased 2012 together with new computers | 1 | The contents of this suite |
| 2 | Windows 7 PRO retail | 1 | 0 | THE-MS-SERIAL | MB-569B | Atea | 2012-11-01 | Purchased 2012 together with new computers | 0 | NULL |
| 3 | Windows 7 PRO retail | 1 | 0 | THE-MS-SERIAL | MB-56C5 | Atea | 2012-11-01 | Purchased 2012 together with new computers | 0 | NULL |
Table volymlicenser:
| id | RegKey | comp_name |
|-----------------------------------|
| 1 | THE-ADOBE-SERIAL | MB-569B |
Desired result according to the SQL select query:
| Program | Computer name | Room | Kommentar|
|-------------------------------------------|
| Adobe Production Premium CS6 | MB-569B | 4.1 | NULL |
|-------------------------------------------|
Desired result when querying for Windows 7 PRO retail:
| Program | Computer name | Room | Kommentar|
|-------------------------------------------|
| Windows 7 PRO Retail | MB-569B | 4.1 | NULL |
| Windows 7 PRO Retail | MB-56C5 | 1.1 | NULL |
Desired result if the "WHERE" was changed to "Windows 7 PRO Retail"
Simply put, if program.VL is 1, the comp_name will be found in the volymlicenser.comp_name column.
If program.VL is 0, the comp_name will be found in program.comp_name column.
Uppon finding the comp_name, it needs to join comp_name from any of these tables on datorer.comp_name to get the room number.
I hope that this makes as much sense to you as it does to me.
Take a look at COMP_NAME in PROGRAM -- it's NULL for the Adobe product. In following, the first regular join you wrote cut the Adobe out of the results. So, after the first join, you just ended up with the the Microsoft products. And then the second join using Reg_Key would have gotten you an empty table because the remaining RegKeys refer solely to "THE-MS-SERIAL".
Instead...
SELECT prog.namn, coalesce(vl.comp_name, prog.comp_name), pc.room, pc.kommentar
FROM program as prog LEFT JOIN volymlicenser as vl
ON prog.RegKey = vl.RegKey
LEFT JOIN dataorer as pc
ON coalesce(vl.comp_name, prog.comp_name) = pc.comp_name
The use of left joins will preserve the contents of the tables to the left of the join syntax. This join method is required because the join keys are not consistently filled out through all three tables. And the coalesce function acts like an ifelse function. If the first variable is null then it is replaced with the contents of the next variable. Nifty.
By the way, I haven't run this myself.
You're probably better off creating 2 inline tables, one with each of your JOIN configurations, then using a CASE to decide which to select from:
SELECT
CASE WHEN table1.column1 = "A"
THEN table2.column2
ELSE
table1.column2
END
FROM
(SELECT t1.id, t1.column1, t2.column2
FROM t1 INNER JOIN t2 ON t1.x = t2.y) table1 INNER JOIN
(SELECT t1.id, t1.column1, t3.column2
FROM t1 INNER JOIN t3 ON t1.x = t2.y) table2 ON table1.id = table2.id;
I am trying the following:
SELECT
CASE WHEN program.VL = "1"
THEN Volymlicenser.comp_name AS Datornamn
ELSE
program.comp_name AS Datornamn
END
FROM
(SELECT prog.Namn AS Program, pc.room AS Room, pc.kommentar AS Komentar
FROM program AS prog INNER JOIN Volymlicenser AS vlic ON vlic.RegKey = prog.RegKey) table1 INNER JOIN
(SELECT t1.id, t1.column1, t3.column2
FROM t1 INNER JOIN t3 ON t1.x = t2.y) table2 ON table1.id = table2.id;
but come to a grinding halt at the select's..
I seriously don't understand the table1, table2, t1, t2 and t3 here.
loltempast: Could you (or anyone) please claryfy as I don't seem to understand how the query should be made.