Join Clause With a XOR Statement - sql

I am doing a join and I can't seem to make this XOR to properly work.
SELECT t1.COMPANY, t1.MILES,
CASE WHEN t2.MILES IS NULL THEN t3.MILES
ELSE t2.MILES
END AS MILES2,
CASE WHEN t2.MILES = t1.MILES AND t2.MILES != 9999 THEN t2.FLATRATE
ELSE t3.RATEBASIS
END AS RATE
FROM TABLE1 AS t1
LEFT JOIN TABLE2 AS t2
ON t1.[COMPANY] = t2.[COMPANYCODE] AND (t1.[MILES] = t2.[MILES])
INNER JOIN (
SELECT TOP 1 TRUCKERCODE, MILES, RATEBASIS, FLATRATE FROM TABLE2 WHERE MILES = 9999
) AS t3
ON t1.[COMPANY] = t3.[COMPANYCODE]
I need the ON clause to join if the miles are the same then get the given fields that match otherwise the default data I need to get out of the second table is where the miles is equal to 9999. Right now with that ON clause I get many extra rows where the MILES equals lets say 45, it gets the data from TABLE2 where miles equals 45 and all the data where miles equals 9999. I need it to do one or the other but not both. This is what my tables would look like
TABLE1 TABLE2
ID COMPANY MILES ETC ID COMPANYCODE MILES RATE
1 ILLINI 50 1 ILLINI 50 3.2
2 ILLINI 110 2 ILLINI 110 5.2
3 ILLINI 150 3 ILLINI 150 2.4
4 ILLINI 200 4 ILLINI 200 1.9
5 ILLINI 250 5 ILLINI 9999 1.5
6 ILLINI 300
7 ILLINI 350
8 ILLINI 400
9 ILLINI 450
10 ILLINI 500
Desired Output
COMPANY MILES MILES2 RATE
ILLINI 50 50 3.2
ILLINI 110 110 5.2
ILLINI 150 150 2.4
ILLINI 200 200 1.9
ILLINI 250 9999 1.5
ILLINI 300 9999 1.5
ILLINI 350 9999 1.5
ILLINI 400 9999 1.5
ILLINI 450 9999 1.5
ILLINI 500 9999 1.5

I think this will give you what you want:
SELECT t1.COMPANY, t1.MILES,
CASE WHEN t2.MILES IS NULL THEN t3.MILES
ELSE t2.MILES
END AS MILES2,
CASE WHEN t2.MILES IS NULL THEN t3.RATE
ELSE t2.RATE
END AS RATE
FROM TABLE1 AS t1
LEFT JOIN TABLE2 AS t2
ON t1.[COMPANY] = t2.[COMPANYCODE] AND (t1.[MILES] = t2.[MILES])
INNER JOIN (
SELECT TOP 1 COMPANYCODE, MILES, RATE FROM TABLE2 WHERE MILES = 9999
) AS t3
ON t1.[COMPANY] = t3.[COMPANYCODE]
If there is a match in MILES, then output contains both records from TABLE1, TABLE2. Otherwise, output contains record from left table, i.e. TABLE1 and the specific record from TABLE2 with MILES = 9999.
Please note that TOP 1 is used in the last sub-query just in case more than one records with MILES = 9999 exist in TABLE2.
Output:
COMPANY MILES MILES2 RATE
----------------------------
ILLINI 50 50 3,2
ILLINI 110 110 5,2
ILLINI 150 150 2,4
ILLINI 200 200 1,9
ILLINI 250 9999 1,5
ILLINI 300 9999 1,5
ILLINI 350 9999 1,5
ILLINI 400 9999 1,5
ILLINI 450 9999 1,5
ILLINI 500 9999 1,5
SQL Fiddle Demo here

I would do based on a double left-join.. once for a match, and if not, then default to the 9999 instance
SELECT
T1.*,
coalesce( T2.miles, T3.miles ) as Miles2,
coalesce( T2.rate, T3.rate ) as MileageRate
FROM
TABLE1 T1
LEFT JOIN TABLE2 T2
on T1.Company = T2.CompanyCode
AND T1.Miles = T2.Miles
LEFT JOIN TABLE2 T3
on T1.Company = T3.CompanyCode
AND T3.Miles = 9999
Confirmed working at this SQL Fiddle link

Related

Merging Two Tables and Calculating Amount (Currency Conversion)

I have table which contains the currency exchange rates and another one with converted amounts.
Currency Table
This table will have the daily rates of the currency. For the ease of mapping I have only included rates for one date.
Branch Code Rate Date
A 0 1 30/10/2019
A 1 200 30/10/2019
A 2 300 30/10/2019
B 0 1 30/10/2019
B 1 10 30/10/2019
B 2 30 30/10/2019
Converted Amounts Table
This table will have the daily exchange details. For the ease of mapping I have only included transactions for one date.
Branch Code Amt Date
A 0 1000 30/10/2019
A 1 2000 30/10/2019
A 2 3000 30/10/2019
A 2 4000 30/10/2019
A 2 5000 30/10/2019
A 0 6000 30/10/2019
B 0 7000 30/10/2019
B 0 8000 30/10/2019
B 0 9000 30/10/2019
B 2 10000 30/10/2019
Resultant Table
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 200 1400000
B 0 30/10/2019 8000 A 1 200 1600000
B 0 30/10/2019 9000 A 1 200 1800000
B 2 30/10/2019 10000 A 2 300 3000000
I could only get the following resultant table.
Branch Code Date Amt Branch Code Rate Total
A 0 30/10/2019 1000 A 0 1 1000
A 1 30/10/2019 2000 A 1 200 400000
A 2 30/10/2019 3000 A 2 300 900000
A 2 30/10/2019 4000 A 2 300 1200000
A 2 30/10/2019 5000 A 2 300 1500000
A 0 30/10/2019 6000 A 1 1 6000
B 0 30/10/2019 7000 A 1 1 7000
B 0 30/10/2019 8000 A 1 1 8000
B 0 30/10/2019 9000 A 1 1 9000
B 2 30/10/2019 10000 A 2 300 3000000
Query I use.
SELECT
*
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(
CASE WHEN code = '0'
AND branch = 'B' THEN '1' ELSE code END
) AS new_code,
branch,
date,
rate
FROM
currency_table
) t2 ON (
t1.date = t2.date
AND t1.code = t2.new_code
)
WHERE
t1.date >= '01-Jan-2019'
AND t1.date <= '30-Sep-2019'
I was able to get the resultant table.
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=4d5401320bda5ad736070541d55d1d04
SELECT
t1.branch,
t1.date2,
t1.code,
t2.code,
t2.new_code,
t2.rate,
t1.amt,
t1.amt * t2.rate AS Total
FROM
converted_amounts_table t1
LEFT OUTER JOIN (
SELECT
(CASE WHEN code = 1 THEN 0 ELSE code END) AS new_code,
branch,
date1,
code,
rate
FROM
currency_table
WHERE
branch = 'A'
) t2 ON (
t1.date2 = t2.date1
AND t1.code IN (t2.new_code, t2.code)
)
WHERE
t1.date2 = '30 - Oct - 2019'
AND (
t1.branch, t1.code, t2.code, t2.new_code,
t2.rate
) NOT IN (
('B', 0, 0, 0, 1),
('A', 0, 1, 0, 200)
)

Properly 'Joining' two Cross Applies

I've got a query with three Cross-Applies that gather data from three different tables. The first Cr-Ap assists the 2nd and 3rd Cr-Ap's. It finds the most recent ID of a certain refill for a 'cartridge', the higher the ID the more recent the refill.
The second and third Cr-Ap's gather the SUMS of items that have been refilled and items that have been dispensed under the most recent Refill.
If I run the query for Cr-Ap 2 or 3 separately the output would look something like:
ID Amount
1 100
2 1000
3 100
4 0
5 0
etc
Amount would be either the amount of dispensed or refilled items.
Only I don't want to run these queries separately, I want them next to each other.
So what I want is a table that looks like this:
ID Refill Dispense
1 100 1
2 1000 5
3 100 7
4 0 99
5 0 3
etc
My gut tells me to do
INNER JOIN crossaply2 ON crossapply3.ID = crossapply2.ID
But this doesn't work. I'm still new to SQL so I don't exactly know what I can and can't join, what I do know is that you can use crossapply as a join (sorta?). I think that might be what I need to do here, I just don't know how.
But that's not it, there's another complication, there are certain refills where nothing gets dispensed. In these scenarios the crossapply I wrote for dispenses won't return anything for that refillID. With nothing I don't mean NULL, I mean it just skips the refillID. But I'd like to see a 0 in those cases. Because it just skips over those ID's I can't get COALESCE or ISNULL to work, this might also complicate the joining of these two applies. Because an INNER JOIN would skip any line where there is no Dispensed amount, even though there is a Refilled amount Id like to see.
Here is my code:
-- Dispensed SUM and Refilled SUM combined
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id]
,Refills.Refilled
,Dispenses.Dispensed
FROM [CartridgeRefill]
CROSS APPLY(
SELECT MAX([CartridgeRefill].[Id]) AS RecentRefillID
FROM [CartridgeRefill]
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS RecentRefill
CROSS APPLY(
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id] AS RefilledID
,SUM([CartridgeRefillMedication].[Amount]) AS Refilled
FROM [CartridgeRefillMedication]
INNER JOIN [CartridgeRefill] ON [CartridgeRefillMedication].[FK_CartridgeRefill_Id] = [CartridgeRefill].[Id]
WHERE [CartridgeRefillMedication].[FK_CartridgeRefill_Id] = RecentRefill.RecentRefillID
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS Refills
CROSS APPLY(
SELECT [CartridgeRefill].[FK_CartridgeRegistration_Id] AS DispensedID
,SUM([CartridgeDispenseAttempt].[Amount]) AS Dispensed
FROM [CartridgeDispenseAttempt]
INNER JOIN [CartridgeRefill] ON [CartridgeDispenseAttempt].[FK_CartridgeRefill_Id] = [CartridgeRefill].[Id]
WHERE [CartridgeDispenseAttempt].[FK_CartridgeRefill_Id] = RecentRefill.RecentRefillID
GROUP BY [CartridgeRefill].[FK_CartridgeRegistration_Id]
) AS Dispenses
GO
The output of this code is as follows:
1 300 1
1 300 1
1 200 194
1 200 194
1 200 8
1 200 8
1 0 39
1 0 39
1 100 14
1 100 14
1 200 1
1 200 1
1 0 28
1 0 28
1 1000 102
1 1000 102
1 1000 557
1 1000 557
1 2000 92
1 2000 92
1 100 75
1 100 75
1 100 100
1 100 100
1 100 51
1 100 51
1 600 28
1 600 28
1 200 47
1 200 47
1 200 152
1 200 152
1 234 26
1 234 26
1 0 227
1 0 227
1 10 6
1 10 6
1 300 86
1 300 86
1 0 194
1 0 194
1 500 18
1 500 18
1 1000 51
1 1000 51
1 1000 56
1 1000 56
1 500 48
1 500 48
1 0 10
1 0 10
1 1500 111
1 1500 111
1 56 79
1 56 79
1 100 6
1 100 6
1 44 134
1 44 134
1 1000 488
1 1000 488
1 100 32
1 100 32
1 100 178
1 100 178
1 500 672
1 500 672
1 200 26
1 200 26
1 500 373
1 500 373
1 100 10
1 100 10
1 900 28
1 900 28
2 900 28
2 900 28
2 900 28
etc
It is total nonsense that I can't do much with, it goes on for about 20k lines and goes through all the ID's, eventually.
Any help is more than appreciated :)
Looks like overcomplicated a bit.
Try
WITH cr AS (
SELECT [FK_CartridgeRegistration_Id]
,MAX([CartridgeRefill].[Id]) RecentRefillID
FROM [CartridgeRefill]
GROUP BY [FK_CartridgeRegistration_Id]
)
SELECT cr.[FK_CartridgeRegistration_Id], Refills.Refilled, Dispenses.Dispensed
FROM cr
CROSS APPLY(
SELECT SUM(crm.[Amount]) AS Refilled
FROM [CartridgeRefillMedication] crm
WHERE crm.[FK_CartridgeRefill_Id] = cr.RecentRefillID
) AS Refills
CROSS APPLY(
SELECT SUM(cda.[Amount]) AS Dispensed
FROM [CartridgeDispenseAttempt] cda
WHERE cda.[FK_CartridgeRefill_Id] = cr.RecentRefillID
) AS Dispenses;

SQL oracle - Delete Duplicate Records and update records in other table

Requirement - Delete Duplicate records e.g. from 2 tables and update the records in the other tables.
Input
Table1 Dim_Ctry
PK_Key1 Country
100 Argentina
200 ARGENTINA
300 India
400 INDIA
Table2 Dim_Geo
PK_Key2 Geo
500 Globe
600 GLOBE
700 Market
800 MARKET
900 Unique
Table Fact1
PK_Key15 FK_KEY1 FK_KEY2
1 100 500
2 200 600
3 300 800
4 400 900
Table Fact2
PK_Key16 FK_KEY1 FK_KEY2
5 100 500
6 200 600
7 200 700
8 300 800
output
Table1 Dim_Ctry
PK_Key1 Country
100 Argentina
300 India
Table2 Dim_Geo
PK_Key2 Geo
500 Globe
700 Market
900 Unique
Table Fact1
PK_Key15 FK_KEY1 FK_KEY2
1 100 500
2 100 500
3 300 800
4 300 800
Table Fact2
PK_Key16 FK_KEY1 FK_KEY2 comment
5 100 500
6 100 500
7 100 700
7 300 800
8 1000 2000 no record in dim table just retain
You will need several steps.
Step 1 update related tables
Update all FK_KEY to the min value.
UPDATE Fact1 f1
SET
FK_KEY1 = (SELECT MIN(PK_Key1)
FROM Dim_Ctry dc1
WHERE UPPER(dc1.Country) = (SELECT UPPER(dc2.Country)
FROM Dim_Ctry dc2
WHERE dc2.PK_Key1 = f1.FK_KEY1)
),
FK_KEY2 = (SELECT MIN(PK_Key2)
FROM Dim_Geo dg1
WHERE UPPER(dg1.Geo) = (SELECT UPPER(dg2.Geo)
FROM Dim_Geo dg2
WHERE dg2.PK_Key2 = f1.FK_KEY2)
);
Step 2 delete duplicated
This will delete all duplicated and keep the one with smaller id
DELETE FROM Dim_Ctry dc1
WHERE EXISTS (SELECT PK_Key1
FROM Dim_Ctry dc2
WHERE dc1.PK_Key1 > dc2.PK_Key1
and UPPER(dc1.Country) = UPPER(dc2.Country)
Step 3 update the text
You should update to lower or upper to standard format.
UPDATE Dim_Ctry
SET Country = UPPER(Country)
debug query
SELECT f1.PK_Key15, f1.FK_KEY1, f1.FK_KEY2,
(SELECT UPPER(dc2.Country)
FROM Dim_Ctry dc2
WHERE dc2.PK_Key1 = f1.FK_KEY1
) as CurrentName,
(SELECT MIN(PK_Key1)
FROM Dim_Ctry dc1
WHERE UPPER(dc1.Country) = (SELECT UPPER(dc2.Country) FROM Dim_Ctry dc2 WHERE dc2.PK_Key1 = f1.FK_KEY1) ) as minKey
FROM Fact1 f1

adding two columns in two tables having multiple layers

I am having two tables here from which I needed to add two columns.
table 1 table 2
1 ram 100 null 1 ram 100 1000
2 ram 200 1000 2 ram 200 null
3 ram 100 2000 3 ram 100 3000
4 ram 100 3000 4 ram 100 4000
5 ram 100 null 5 ram 100 5000
1 rahim 100 5000 1 rahim 100 null
2 ram 200 6000 2 ram 200 7000
3 ram 200 null 3 ram 200 8000
4 ram 200 null 4 ram 200 9000
5 rahim 100 9000 5 rahim 100 null
1 robert 100 10000 1 robert 100 11000
2 rahim 200 11000 2 rahim 200 12000
3 ram 300 12000 3 ram 300 null
4 rahim 400 13000 4 rahim 400 14000
5 robert 100 14000 5 robert 100 15000
result should be in the form:
1 ram 100 1000
2 ram 200 -1000
3 ram 100 1000
4 ram 100 1000
5 ram 100 5000
1 rahim 100 -5000
2 ram 200 1000
3 ram 200 8000
4 ram 200 9000
5 rahim 100 -9000
1 robert 100 1000
2 rahim 200 1000
3 ram 300 -12000
4 rahim 400 1000
5 robert 100 1000
You can use join with coalesce to remove the null values:
select t1.id, t1.somefield, t1.someint,
coalesce(t2.someint2,0)-coalesce(t1.someint2,0)
from table1 t1
join table2 t2 on t1.id = t2.id
and t1.somefield = t2.somefield
and t1.someint = t2.someint
SQL Fiddle Demo
Based on your input data, this joins on the first 3 columns. Not completely sure this is what you want, but should get you going in the correct direction.
I think try subtract table2.col4 with table1.col4.
SELECT a.col1,
a.col2,
a.col3,
NVL(a.col4, 0) - NVL(b.col4, 0) SUB
FROM table1 A
JOIN table2 B
ON A.col1 = b.col1
AND a.col2 = b.col2

SQL join two table together

I have the following tables:
table1
a b
1 100
2 200
3 300
4 400
table2
c b
55 100
55 200
56 300
I want to get the following output:
55 100 1
55 200 2
55 300 -
55 400 -
56 100 -
56 200 -
56 300 3
56 400 -
I tried the following:
SELECT *
FROM table1
full JOIN table2
output:
a b c a
1 100 55 100
1 100 55 200
1 100 55 100
1 100 55 200
2 300 56 300
....
also I tried:
SELECT *
FROM table1
join table2 on table1.b = table2.b
union
SELECT *
FROM table2
join table1 on table1.b = table2.b
the output:
1 100 55 100
1 200 55 200
3 300 56 300
Is this possible in microsoft SQL 2012? and how
I'm not completely sure I understand your expected outcome, but it sounds like you're looking for a FULL OUTER JOIN.
SELECT table1.a, COALESCE(table1.b, table2.b), table2.c
FROM table1
FULL OUTER JOIN table2 ON table1.b = table2.b
This will get the fields from table1 and, if any exist, map them to those from table2.
Given your example, it will return the following table.
A B C
1 100 55
2 200 55
3 300 56
4 400 (null)
I know that isn't the same as the expected result you gave, but this will correlate the data that actually exists.
I'm requesting clarification in a comment and will revise this as necessary.