Oracle SQL - Where Not Exists and multiple joins - sql

I'm in need of some assistance to anyone familiar with Oracle SQL. I'm trying to use the Where Not Exists sub query, and is working fine with specific where clauses for specific customers, and then using UNION to join any other customer thereafter. I'm trying to use the SQL in a way where I'm not using UNION to join multiple customers, as there's 100's. I just don't know how to go about it.
I think I need to join the MAIN_ITEM table to the LOCATION table somehow, as it links the items in INVENTORY_LOCATIONS with a zone_code where the location_code can be compared against the table ZONE, showing any mismatches where location_code in INVENTORY_LOCATIONS does not exist in table ZONE. I'm not really sure if I"m explaining this properly, but hopefully my example below clears it up.
Many thanks in advance.
Current Query
select a.company, a.customer, c.customer_name, a.location_code, a.invt1, a.invt2, a.invt3, a.invt_qty
from inventory_locations a left join main_customer c
on a.company=c.company and a.customer=c.customer and a.ware_code=c.ware_code
where not exists (select 1 from zone b where b.location_code = a.location_code and b.zone_code='PM')
and a.company='M1'
and a.customer='100068'
UNION
select a.company, a.customer, c.customer_name, a.location_code, a.invt1, a.invt2, a.invt3, a.invt_qty
from inventory_locations a left join main_customer c
on a.company=c.company and a.customer=c.customer and a.ware_code=c.ware_code
where not exists (select 1 from zone b where b.location_code = a.location_code and b.zone_code='Z1')
and a.company='M1'
and a.customer='100012'
Table 1 - INVENTORY_LOCATIONS A
COMPANY | WARE_CODE |CUSTOMER | LOCATION_CODE |INVT1 | INVT2 | INVT3 | INVT_QTY
--------------------------------------------------------------------------------------
M1 | 01 | 100012 | 0101A |000052 | T100 | 000001001 | 60
M1 | 01 | 100012 | 0602A |000053 | T101 | 000001002 | 60
M1 | 01 | 100068 | 0601A |CANDY | T200 | 000001080 | 25
M1 | 01 | 100068 | 0102A |CANDY2 | T202 | 000001081 | 25
Table 2 - ZONE B
COMPANY | WARE_CODE |ZONE_CODE | LOCATION_CODE
--------------------------------------------------------
M1 | 01 |PM | 0101A
M1 | 01 |PM | 0102A
M1 | 01 |Z1 | 0601A
M1 | 01 |Z1 | 0602A
Table 3 - MAIN_ITEM D
COMPANY | WARE_CODE | CUSTOMER | ITEM_CODE | ZONE_CODE
----------------------------------------------------------------
M1 | 01 | 100012 | 000052 | PM
M1 | 01 | 100012 | 000053 | PM
M1 | 01 | 100068 | CANDY | Z1
M1 | 01 | 100068 | CANDY2 | Z1
Current results with above query.
COMPANY | CUSTOMER | CUSTOMER_NAME | LOCATION_CODE | INVT1 | INVT2 | INVT3 | INVT_QTY
---------------------------------------------------------------------------------------------------
M1 | 100012 | TEST COMP 1 | 0602A | 000053 | T101 | 000001002 | 60
M1 | 100068 | TEST COMP 2 | 0102A | CANDY2 | T202 | 000001081 | 25
Expected results with a query that doesn't use UNION to join multiple customers.
COMPANY | CUSTOMER | CUSTOMER_NAME | LOCATION_CODE | INVT1 | INVT2 | INVT3 | INVT_QTY
-------------------------------------------------------------------------------------------------
M1 | 100012 | TEST COMP 1 | 0602A | 000053 | T101 | 000001002 | 60
M1 | 100068 | TEST COMP 2 | 0102A | CANDY2 | T202 | 000001081 | 25
Thank you for taking the time to read and assist. Greatly appreciated.

I don't fully understand the semantics of your tables and am not sure of the primary keys which means the join conditions could need to be corrected.
However, my interpretation of your goal is to find which inventory_location rows imply a combination of location code and zone that is not in the zone table.
So I would do as follows:
Take the inventory_location table, and add on the customer_name and zone_code with joins. I am assuming each row has only one customer and only one zone. A "with" clause is convenient to treat this as if it were a single table.
Then take the location and zone code combinations and see which ones are missing from the zone table with a "where not exists" clause.
I apologize in advance for any typos/syntax errors. Without actually executing it, I think it would produce your requested output.
with inv_loc as (
select a.company, a.customer, c.customer_name, a.location_code, a.invt1, a.invt2, a.invt3, a.invt_qty, d.zone_code
from inventory_locations a
left join main_customer c on a.company=c.company and a.customer=c.customer and a.ware_code=c.ware_code
left join main_item d on d.company = a.company and d.customer = a.customer and d.ware_code = a.ware_code and d.item_code = a.invt1
)
select
company, customer, customer_name, location_code, invt1, invt2, invt3, invt_qty
from inv_loc i
where not exists (
select 1 from zone b
where b.location_code = i.location_code and b.zone_code =i.zone_code
)

Related

SQL Group By and Join based on a weird client table

I have 3 tables that I want to join together and group it to get client membership info. My code works for grouping the base table together but it breaks at the join part and I can't figure out why.
BASE TABLE : sales_detail
+-------+-----------+-----------+-----------------------------------------+
| order_date | transaction_id| product_cost | payment_type | country
+-------+-----------+-----------+------------------------------------------+
| 10/1 | 12345 | 20 | mastercard | usa
| 10/1 | 12345 | 50 | mastercard | usa
| 10/5 | 82456 | 50 | mastercard | usa
| 10/9 | 64789 | 30 | visa | canada
| 10/15 | 08546 | 20 | mastercard | usa
| 10/15 | 08546 | 90 | mastercard | usa
| 10/17 | 65898 | 50 | mastercard | usa
+-------+-----------+-----------+-------------------------------------+
table : client_information
+-------+-----------+-----------+-------------------+
| other_id | client_Type | item
+-------+-----------+-----------+----------+
| 112341 | new | hola |
| 112341 | old | mango |
| 145634 | old | pine |
| 879547 | old | vip |
| 745688 | new | unio |
| 745688 | old | dog |
| 147899 | new | cat |
| 124589 | new | amigo |
+-------+-----------+-----------+-----------+
table : connector
+-------+-----------+-----------+-------------------+
| transaction_ID | other_id | item
+-------+-----------+-----------+----------+
| 12345 | 112341 | hola |
| 82456 | 145634 | pine |
| 08157 | 879547 | unio |
| 08546 | 745688 | dog |
| 65898 | 147899 | cat |
| 06587 | 124589 | amigo |
+-------+-----------+-----------+-----------+
**I want the output to look something like this: **
IDEAL OUTPUT
+-------+-----------+-----------+--------------------------------+
| order_date | transaction_ID | product_cost | client_Type|
+-------+-----------+-----------+--------------------------------+
| 10/1 | 12345 | 70 | new |
| 10/5 | 82456 | 70 | old |
| 10/15 | 08546 | 110 | old |
| 10/17 | 65898 | 50 | new |
+-------+-----------+-----------+----------------------------------+
**i am trying to join my base table to the connector table by transaction ID to get other_id and items to match to client_type **
This is the code i used but it failed to compile after adding in left joins :
select t1.transaction_id, sum(t1.product_cost), t1.order_date, t3.client_type
from sales_detail t1
left join (select DISTINCT transaction_ID, other_id, fruits from connector) t2
ON t1.transaction_ID=t2.transaction_ID
left join (select DISTINCT order_id, client_type, fruits from client information) t3
ON t2.other_id=t3.other_id and t2.item=t3.item
where t1.payment_type='mastercard' and t1.order_Date between '2020-10-01' and'2020-10-31'
and country != 'canada'
GROUP BY t1.transaction_id, t1.order_date, t3.client_type;
Thanks in advance! I am a beginner so still learning the ins and outs of sql! (am using hive)
I think that's joins and aggregation. For more efficiency, you can pre-aggregate in a subquery, then join:
select sd.*, ci.client_type
from (
select order_date, transaction_id, sum(product_cost) product_cost
from sales_detail
where
payment_type = 'mastercard'
and order_date >= '2020-10-01'
and order_date < '2020-11-01'
and country <> 'canada'
group by order_date, transaction_id
) sd
inner join connector c on c.transaction_id = sd.transaction_id
inner join client_information ci on ci.other_id = c.other_id
Note that I rewrote the filter on order_date to use half-open intervals rather than between. This properly handles the case when your dates have a time portion.
From what I have understood, your code works although not as you would like using an INNER JOIN and it fails to add a LEFT JOIN. I think what happens is a failure due to the NULL elements. to add a NULL element and not get an error, you have to use some function that changes the NULL value to 0 .
One such function is the ISNULL(yourColumn, 0) function of T-SQL.The documentation.
I can see that in result table you only need clients who used mastercard, so you should use inner join there so only those client who used mastercard will be considered. While the remaining query is okay i guess, but main problem was the join on client information.
I think on the answer with GMB you also need to join on item column otherwise you will get multiple rows output.
select sd.*, ci.client_type
from (
select order_date, transaction_id, sum(product_cost) product_cost
from sales_detail
group by order_date, transaction_id
) sd
inner join connector c on c.transaction_id = sd.transaction_id
inner join client_information ci on ci.other_id = c.other_id and ci.item = c.item
Just modify with your filters and you should be sorted.

MS Access duplicate values using SUM

I'm having trouble writing a query in Microsoft Access 2016 that will show the sum of an Expense for a particular event, the sum of the signs that event produced, along with the year, event description and company name.
I think I am missing something simple, and am going to feel ridiculous once someone points it out. Hopefully I managed to format my question well enough that it is easy to spot!
Here are the tables involved, along with the dummy data I am testing with.
All_Company Company_Event
------------------ ---------------------------
| ID | Company | | ID | EventDescription |
|------|---------| |----|--------------------|
| 1 | Crapple | | 1 | Concert |
| 2 | Rito | | 2 | Party |
------------------ ---------------------------
Company_Target_Actual
----------------------------------------------------------------
| All_CompanyID | Company_EventID | Year | Quarter | Signed |
|----------------|-------------------|------|---------|--------|
| 1 | 2 | 2015 | 1 | 1 |
| 1 | 2 | 2015 | 2 | 0 |
| 1 | 2 | 2015 | 3 | 3 |
| 1 | 2 | 2015 | 4 | 1 |
----------------------------------------------------------------
Budget_Company_Expense
---------------------------------------------------------------------------------
| ID | All_CompanyID | Company_EventID | Year | Category | SubCategory| Expense |
---------------------------------------------------------------------------------
| 1 | 1 | 2 | 2015 | ABCD | 123 | 40 |
| 2 | 1 | 2 | 2015 | ABCD | cat | 113 |
| 3 | 1 | 2 | 2015 | ABCD | dog | 71 |
---------------------------------------------------------------------------------
This is my code for the query, I broke it up from the ugly Access long lines of code to make it easier to read.
SELECT DISTINCTROW All_Company.Company, Budget_Company_Expense.Year,
Budget_Company_Expense.Company_EventID, Company_Event.EventDescription,
Sum(Budget_Company_Expense.Expense) AS [Sum Of Expense USD],
Sum(Company_Target_Actual.Signed) AS [Sum Of Signed]
FROM Company_Event
INNER JOIN ((All_Company
INNER JOIN Company_Target_Actual
ON All_Company.[ID] = Company_Target_Actual.[All_CompanyID])
INNER JOIN Budget_Company_Expense
ON All_Company.[ID] = Budget_Company_Expense.[All_CompanyID])
ON Company_Event.[ID] = Budget_Company_Expense.[Company_EventID]
GROUP BY All_Company.Company, Budget_Company_Expense.Year,
Budget_Company_Expense.Company_EventID, Company_Event.EventDescription;
and here is the result from running my query
Result
-------------------------------------------------------------------------------------------
| Company | Year | Company_EventID | EventDescription | Sum of Expense USD | Sum of Signed|
-------------------------------------------------------------------------------------------
| Crapple | 2015 | 2 | Party | $896.00 | 15 |
-------------------------------------------------------------------------------------------
As you can see, it is summing as if the total signs (5) happened 3 times (the number of entries in the Company_Target_Actual table) and vis versa for the Expense. Any help on my issue would be greatly appreciated,
and if I forgot any information that may help find my mistake please let me know what else I can provide!
Consider splitting the query into two aggregations, one to sum Signed in Company_Target_Actual and the other to sum Expense in Business_Company_Expense. Then, join the two queries by Company, Event, and Year which are the grouping factors.
Below uses two derived tables (subqueries in FROM/JOIN clause). However, you can very well save either one as a separate query and then join them in final query:
SELECT t1.Company, t1.Year, t1.Company_EventID, t1.EventDescription,
t2.[Sum Of Expense USD], t1.[Sum of Signed]
FROM
(SELECT ac.ID AS CompanyID, ac.Company, ca.Year, ca.Company_EventID, ev.EventDescription,
SUM(ca.Signed) AS [Sum Of Signed]
FROM (Company_Target_Actual ca
INNER JOIN Company_Event ev
ON ca.Company_EventID = ev.ID)
INNER JOIN All_Company ac
ON ca.All_CompanyID = ac.ID
GROUP BY ac.ID, ac.Company, ca.Year, ca.Company_EventID, ev.EventDescription) AS t1
INNER JOIN
(SELECT ac.ID AS CompanyID, ac.Company, be.Year, be.Company_EventID, ev.EventDescription,
SUM(be.Expense) AS [Sum Of Expense USD]
FROM (Budget_Company_Expense be
INNER JOIN Company_Event ev
ON be.Company_EventID = ev.ID)
INNER JOIN All_Company ac
ON be.All_CompanyID = ac.ID
GROUP BY ac.ID, ac.Company, be.Year, be.Company_EventID, ev.EventDescription) AS t2
ON t1.CompanyID = t2.CompanyID
AND t1.Company_EventID = t2.Company_EventID
AND t1.Year = t2.Year

Data aggregation with left-outer join

I am trying to pull some data with transaction counts, by branch, by week, which will later be used to feed some dynamic .Net charts.
I have a calendar table, I have a branch table and I have a transaction table.
Here is my DB info (only relevant columns included):
Branch Table:
ID (int), Branch (varchar)
Calendar Table:
Date (datetime), WeekOfYear(int)
Transaction Table:
Date (datetime), Branch (int), TransactionCount(int)
So, I want to do something like the following:
Select b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
LEFT OUTER JOIN TransactionTable t
on t.Branch = b.ID
JOIN Calendar c
on t.Date = c.Date
WHERE YEAR(c.Date) = #Year // (SP accepts this parameter)
GROUP BY b.Branch, c.WeekOfYear
Now, this works EXCEPT when a branch doesn't have any transactions for a week, in which case NO RECORD is returned for that branch on that week. What I WANT is to get that branch, that week and "0" for the sum. I tried isnull(sum(TransactionCount), 0) - but that didn't work, either. So I will get the following (making up sums for illustration purposes):
+--------+------------+-----+
| Branch | WeekOfYear | Sum |
+--------+------------+-----+
| 1 | 1 | 25 |
| 2 | 1 | 37 |
| 3 | 1 | 19 |
| 4 | 1 | 0 | //THIS RECORD DOES NOT GET RETURNED, BUT I NEED IT!
| 1 | 2 | 64 |
| 2 | 2 | 34 |
| 3 | 2 | 53 |
| 4 | 2 | 11 |
+--------+------------+-----+
So, why doesn't the left-outer join work? Isn't that supposed to
Any help will be greatly appreciated. Thank you!
EDIT: SAMPLE TABLE DATA:
Branch Table:
+----+---------------+
| ID | Branch |
+----+---------------+
| 1 | First Branch |
| 2 | Second Branch |
| 3 | Third Branch |
| 4 | Fourth Branch |
+----+---------------+
Calendar Table:
+------------+------------+
| Date | WeekOfYear |
+------------+------------+
| 01/01/2015 | 1 |
| 01/02/2015 | 1 |
+------------+------------+
Transaction Table
+------------+--------+--------------+
| Date | Branch | Transactions |
+------------+--------+--------------+
| 01/01/2015 | 1 | 12 |
| 01/01/2015 | 1 | 9 |
| 01/01/2015 | 2 | 4 |
| 01/01/2015 | 2 | 2 |
| 01/01/2015 | 2 | 23 |
| 01/01/2015 | 3 | 42 |
| 01/01/2015 | 3 | 19 |
| 01/01/2015 | 3 | 7 |
+------------+--------+--------------+
If you want to return a query that contains each Branch and each week, then you'll need to first create a full list of that, then use a LEFT JOIN to the transactions to get the count. The code will be similar to:
select bc.Branch,
bc.WeekOfYear,
TotalTransaction = coalesce(sum(t.TransactionCount), 0)
from
(
select b.id, b.branch, c.WeekOfYear, c.date
from branch b
cross join Calendar c
-- if you want to limit the number of rows returned use a WHERE to limit the weeks
-- so far in the year or using the date column
WHERE c.date <= getdate()
and YEAR(c.Date) = #Year // (SP accepts this parameter)
) bc
left join TransactionTable t
on t.Date = bc.Date
and bc.id = t.branch
GROUP BY bc.Branch, bc.WeekOfYear
See Demo
This code will create in your subquery a full list of each branch with each date. Once you have this list, then you can JOIN to the transactions to get your total transaction count and you'd return each date as you want.
Bring in the Calendar before you bring in the transactions:
SELECT b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
INNER JOIN CalendarTable c ON YEAR(c.Date) = #Year
LEFT JOIN TransactionTable t ON t.Branch = b.ID AND t.Date = c.Date
GROUP BY b.Branch, c.WeekOfYear
ORDER BY c.WeekOfYear, b.Branch

Sum of count from external table

I need to search for the sum of the games made by specific developers. I have two tables:
_____________________________
|____________GAMES____________|
| Id | Title | id_dev | hits |
| 01 | abc | 1 | 20 |
| 02 | xyz | 2 | 15 |
| 03 | cde | 1 | 9 |
_______________
|__DEVELOPERS___|
| Id | Title |
| 01 | poi |
| 02 | asd |
| 03 | qwe |
I want result formatted like Developers title 40, where 40 is the sum of all hits of the games with the ID of this developer. How can I go about this?
SELECT developers.title, COUNT(count) AS total FROM (SELECT COUNT(games.hits) AS count
FROM games
GROUP BY id_dev
HAVING count > 1) as A
FROM developers
JOIN games
WHERE developers.id = games.id_dev
This is a simple join and aggregate, so you are overcomplicating things:
select d.id, d.title, sum(g.hits)
from games g join
developers d
on g.id_dev = d.id
group by d.id, d.title;

sql compact 3.5, select top n rows from each group

I am writing a query to select the top 1 record from each group. Keep in mind that I working on sql compact 3.5 and thus can not use the rank function. I'm pretty sure my query is incorrect but I'm not sure how to select top from each group. Any one got any ideas?
Here is the query I was trying to get working
/*
* added fH.InvoiceNumber to my query to get result further below.
/
select tH., t.CustomerNumber, c.CustomerName, fH.Status, fH.InvoiceNumber
from tenderHeader tH
join task t ON tH.TaskActivityID = t.ActivityID
join finalizeTicketHeader fH ON tH.FinalizeTicketTaskActivityID = fH.TaskActivityID
join customer c ON t.CustomerNumber = c.CustomerNumber
where fH.Status <> '3' AND t.TripID = '08ea6982-6efd-46fa-9753-0fd8b076f24c';
Here is what my tables look like:
customer table:
|------------------------------------------------|
| CustomerNumber | CustomerName | Address1 | ... |
|------------------------------------------------|
| 0012084737 | Customer A | 150 Rd A | ... |
|------------------------------------------------|
| 0012301891 | Customer B | 152 Rd A | ... |
|------------------------------------------------|
task table
|-----------------------------------------------------------------|
| ActivityID | TripID | TaskTypeName | Status | CustomerNumber |
|-----------------------------------------------------------------|
| 4967f6cc | 08ea6982 | Payment | 2 | 0012084737 |
|-----------------------------------------------------------------|
| e96469a1 | 08ea6982 | Payment | 2 | 0012301891 |
|-----------------------------------------------------------------|
finalizeTicketHeader table
|---------------------------------------------------|
| TaskActivityID | InvoiceNumber | Amount | Status |
|---------------------------------------------------|
| 916082c8 | 1000 | 563.32 | 3 |
|---------------------------------------------------|
| 916082c8 | 1001 | -343.68 | 0 |
|---------------------------------------------------|
| 4b38bf60 | 1002 | 152.29 | 0 |
|---------------------------------------------------|
| 4b38bf60 | 1003 | -35.80 | 0 |
|---------------------------------------------------|
tenderHeader table
|-------------------------------------------------------------------------------------|
| TaskActivityID | InvoiceNumber | PastDue | TodaysDue | FinalizeTicketTaskActivityID |
|-------------------------------------------------------------------------------------|
| 4967f6cc | 1234567891 | 23.55 | 219.64 | 916082c8 |
|-------------------------------------------------------------------------------------|
| e96469a1 | 1234567893 | 0.00 | 116.49 | 4b38bf60 |
|-------------------------------------------------------------------------------------|
the problem I was having was getting duplicates.
like so:
|------------------------------------------------------------------------------------------------------------------------------------|
| TaskActivityID | InvoiceNumber | PastDue | TodaysDue | FinalizeTicketTaskActivityID | CustomerNumber | CustomerName | InvoiceNumber |
|------------------------------------------------------------------------------------------------------------------------------------|
| 4967f6cc | 1234567891 | 23.55 | 219.64 | 916082c8 | 0012084737 | Customer A | 1001 |
|------------------------------------------------------------------------------------------------------------------------------------|
| e96469a1 | 1234567893 | 0.00 | 116.49 | 4b38bf60 | 0012301891 | Customer B | 1002 |
|------------------------------------------------------------------------------------------------------------------------------------|
| e96469a1 | 1234567893 | 0.00 | 116.49 | 4b38bf60 | 0012301891 | Customer B | 1003 |
|------------------------------------------------------------------------------------------------------------------------------------|
I've rewritten the query like so, but I need to get specific columns from the sub query.
select tH.* from tenderHeader th
inner join task t on tH.TaskActivityID = t.ActivityID
inner join (
select k.TaskActivityID from finalizeTicketHeader k group by k.TaskActivityID
) as fH on tH.FinalizeTicketTaskActivityID = fH.TaskActivityID
inner join customer c on t.CustomerNumber = c.CustomerNumber
I need to get the status from fH. Any ideas of how to do that?
select tH.*, fH.Status from tenderHeader th
inner join task t on tH.TaskActivityID = t.ActivityID
inner join finalizeTicketHeader fH on tH.FinalizeTicketTaskActivityID = tH.TaskActivityID
inner join customer c on t.CustomerNumber = c.CustomerNumber
where tH.FinalizeTicketTaskActivityID = (
select top (1) k.TaskActivityID from finalizeTicketHeader k
);
but it seems that sql compact 3.5 does not support scalar values with subquery in where cause.
Here is an example that demonstrat a way of selecting the top 1 from each group
id|time
--------
2 | 1:10
2 | 0:45
2 | 1:45
2 | 1:30
1 | 1:00
1 | 1:10
the table is called table_1; we group by id and assume that time should be desc ordered
select table_1.* from table_1
inner join (
select id, max(time) as max_time from table_1
group by id
) as t
on t.max_time = table_1.time and table_1.id = t.id
order by table_1.id
the result we get is
id|time
--------
1 | 1:10
2 | 1:45