Select all rows from joined with multiple conditions tables with null values - sql

I want to join two tables, Sales and Budget.
Sales table columns:
| Customer | Period | Sales |
Budget table columns:
| Customer | Period | SaleBudget |
Sales table has data for periods 1, 2, and 3. Budget has data for periods 1-12. When I try to run below query I get only data for periods from Sales table matched with Budget table. But my goal is to get all data from both tables. Could you give me a hint how to change query?
Select s.Customer, b.SaleBudget, s.Sales from Sales s
full outer join Budget b on b.Customer = s.Customer and b.Period = s.Period

When you use left join its join the rows that are same in
b.Customer = s.Customer and b.Period = s.Period
if you want have all of the rows you shouldn't use left join;
The LEFT JOIN keyword returns all records from the left table (table1), and the matching records from the right table (table2);
there is not any way that get some data matching and some data Inconsistency in one shape.

Related

Redundant values in columns with aggregate function?

SELECT
SUM(total_amt_usd),
sales_rep_id,
sales_reps.name AS salesman,
region.name AS regionname
FROM orders
JOIN accounts
ON orders.account_id = accounts.id
JOIN sales_reps
ON accounts.sales_rep_id = sales_reps.id
JOIN region
ON sales_reps.region_id = region.id
Are the three columns redundant with the SUM aggregate function? SUM I believe has correctly performed its operation of summing all the values (total_amt_usd) in the first column.
SELECT Sum(total_amt_usd),
sales_rep_id,
sales_reps.NAME AS salesman,
region.NAME AS regionname
FROM orders
LEFT JOIN accounts
ON orders.account_id = accounts.id
LEFT JOIN sales_reps
ON accounts.sales_rep_id = sales_reps.id
LEFT JOIN region
ON sales_reps.region_id = region.id
GROUP BY sales_rep_id,
sales_reps.NAME,
region.NAME
They do not look redundant. It seems like a query to find total sales amount summed separately for each sales representative from the orders table. The orders table has the sales representative id, which is used to lookup the representatives name from the joined sales_reps table and that table, in turn has a region_id which is used to look up region name from the joined region table. The final result has rows with id, name, and region of a sales representative along with total amount of orders that sales representative has got.
I think the query should be more like the following for this explanation to make sense:
SELECT
SUM(total_amt_usd),
sales_rep_id,
sales_reps.name AS salesman,
region.name AS regionname
FROM orders
JOIN accounts
ON orders.account_id = accounts.id
JOIN sales_reps
ON accounts.sales_rep_id = sales_reps.id
JOIN region
ON sales_reps.region_id = region.id
GROUP BY sales_rep_id;

SQL Server Left Join producing duplicates

I have 3 tables, Budgets, Income, and Expenses.
Budget table:
Income table:
Expenses table:
This is my SQL statement:
SELECT
Budgets.BudgetID, Budgets.BudgetName, Budgets.Username_FK,
Budgets.BudgetAmount, Budgets.SavePercentage,
Expenses.ExpensesID, Expenses.ExpensesAmount, Expenses.ExpensesCategory,
Income.IncomeID, Income.IncomeAmount, Income.IncomeCategory
FROM
Budgets
LEFT JOIN
Income ON Budgets.BudgetID = Income.BudgetID_FK
LEFT JOIN
Expenses ON Budgets.BudgetID = Expenses.BudgetID_FK
WHERE
BudgetName = '2019
And the results are as follows:
Based on my Income table, there is only 1 record tied to BudgetID = 3, but in the left join, it duplicates.
Ideally, I would want it to return "null" on the duplicates. How do I do this?
You have several rows in expenses per budgetID, so your join produces that many rows. I tend to suspect that the same situation could happen with income too.
If you want one row per budgetID, then one option is pre-aggregation and a left join (or outer apply). Say you want the total expense and income per budget, you would do:
select b.*, e.expenseAmount, i.amountAmount
from budgets b
left join (
select budgetID_FK, sum(expenseAmount) expenseAmount
from expenses
group by budgetID_FK
) e on e.budgetID_FK = b.budgetID
left join (
select budgetID_FK, sum(incomeAmount) incomeAmount
from income
group by budgetID_FK
) i on i.budgetID_FK = b.budgetID
Now you are grouping rows in the dependent tables by budgetID, so you can't see the other columns of these tables, such as incomeCategory or expenseCategory (which have multiple values per budgetID).
For budgetID 3 , you have 4 expenses( distinct expense IDs) of 50.00 in your expense table for the same user. I think what you would want is the total expenses of same category and budget ID i.e budgetID 3 in this case
SELECT
Budgets.BudgetID, Budgets.BudgetName, Budgets.Username_FK,
Budgets.BudgetAmount, Budgets.SavePercentage,
Income.IncomeID, Income.IncomeAmount, Income.IncomeCategory,
ex.ExpensesCategory,
ex.Total_ExpensesAmount,
FROM Budgets
LEFT JOIN Income ON Budgets.BudgetID = Income.BudgetID_FK
LEFT JOIN (Select BudgetID_FK, ExpensesCategory, SUM(ExpensesAmount) as Total_ExpensesAmount
FROM Expenses
GROUP BY BudgetID_FK, ExpensesCategory) ex ON Budgets.BudgetID = ex.BudgetID_FK
WHERE BudgetName = '2019'

How to join the results of two queries in just one table grouped by YEAR and MONTH?

I have two tables,materials_students and components_students. Both of them has afinished_at column. material_student has a component_student_id column.
I need to count the number of components_students and materials_students (Where finished_at id is not NULL), extract month and year from finished_at, group the result by month and year and plot it in just one table, like this:
| Materials | Components | Month | Year
---------------------------------------------
| 45 3 1 2019
| 37 6 2 2019
| 63 8 3 2019
I know how to do this for one table only, but dont know how to join the results in just one table.
Find below how I did for one table:
FROM materials_students
LEFT JOIN students ON materials_students.student_id = students.id
LEFT JOIN company_profiles ON students.company_profile_id = company_profiles.id
LEFT JOIN companies ON company_profiles.company_id = companies.id
WHERE materials_students.finished_at IS NOT NULL
GROUP BY YEAR, MONTH
ORDER BY YEAR, MONTH
Thanks!
The best is to assemble a subquery for each case, then join them.
select
ISNULL(M.yy, C.yy) [yy],
ISNULL(M.mm, C.mm) [mm],
ISNULL(number_material_students, 0) [number_material_students],
ISNULL(number_components_students, 0) [number_component_students]
from (
SELECT
year(materials_students.finished_at) yy,
month(materials_students.finished_at) mm,
count(*) number_material_students
FROM materials_students
LEFT JOIN students ON materials_students.student_id = students.id
LEFT JOIN company_profiles ON students.company_profile_id = company_profiles.id
LEFT JOIN companies ON company_profiles.company_id = companies.id
WHERE materials_students.finished_at IS NOT NULL
GROUP BY year(materials_students.finished_at), month(materials_students.finished_at)
) M
full outer join (
SELECT
year(components_students.finished_at) yy,
month(components_students.finished_at) mm,
count(*) number_material_students
FROM components_students
LEFT JOIN students ON components_students.student_id = students.id
LEFT JOIN company_profiles ON students.company_profile_id = company_profiles.id
LEFT JOIN companies ON company_profiles.company_id = companies.id
WHERE components_students.finished_at IS NOT NULL
GROUP BY year(materials_students.finished_at), month(materials_students.finished_at)
) C
ON C.yy = M.yy AND C.mm = M.mm
ORDER BY 1, 2
I had to make a FULL OUTER JOIN between the subqueries, because there may have been year/months that appear only on materials, but not on components, and vice-versa.
To retrieve the year I use the ISNULL() function, so in case year is not filled from the materials subquery, I use it from the components subquery. Similar reasoning applies to all other resulting columns.

Create View having trouble with JOINS

I have 5 regions that each contain 1 store and 1 warehouse. I have a table that contains the regions and corresponding stores and warehouses. I also have a table that lists the inventories of both the stores and warehouses. Finally, have a table that lists the allowed quantities for the warehouse. If I look at the inventory table right now it would say something like:
FACILITY ID ITEM_NUMBER QTY
STORE 1 15D 2
WAREHOUSE 1 15D 1
The problem is, Store 1 and Warehouse 1 belong to region 1 and I would like to see it in this format:
REGION WAREHOUSE QTY OH STORE QTY OH
1 1 2 1 1
and so on... So I wrote the following SQL:
Create or replace view REGION_BALANCES
as
with WAREHOUSES as
(
select
A.REGION_CODE,A.REG_DESC,A.WAREHOUSE_NUMBER,A.FACILITY_ID,C.ITEM_NUMBER,sum(C.IN_STOCK_QTY) as IN_STOCK_QTY, B.ALLOWED_QTY
from REG_WHS_STR_ASSOC A
join ALLOWANCES B on (A.FACILITY_ID = B.FACILITY_ID)
join INVENTORIES C on (A.FACILITY_ID = FACILITY_ID) and B.ITEM_NUMBER = C.ITEM_NUMBER)
group by A.REGION_CODE,A.REG_DESC,A.WAREHOUSE_NUMBER,C.ITEM_NUMBER,B.ALLOWED_QTY
),
STORES as
(
select
A.REGION_CODE,A.REG_DESC,A.STORE_NUMBER,A.FACILITY_ID,B.ITEM_NUMBER,sum(B.IN_STOCK_QTY) as IN_STOCK_QTY
from REG_WHS_STR_ASSOC A
join INVENTORIES B on (A.FACILITY_ID = B.FACILITY_ID)
group by A.REGION_CODE,A.REG_DESC,A.STORE_NUMBER, B.ITEM_NUMBER
)
select A.REGION_CODE,A.REG_DESC,A.WAREHOUSE_NUMBER,A.FACILITY_ID,WAREHOUSES.ITEM_NUMBER,WAREHOUSES.IN_STOCK_QTY,WAREHOUSES.ALLOWED_QTY,STORES.STORE_NUMBER,STORES.FACILITY_ID,STORES.ITEM_NUMBER,STORES.IN_STOCK_QTY
from REG_WHS_STR_ASSOC A
join WAREHOUSES on (A.REGION_CODE = WAREHOUSES.REGION_CODE)
join STORES on (A.REGION_CODE = STORES.REGION_CODE)
order by 5,1 asc;
I have changed my join around from left joins to right joins to cross joins to inner joins; however, I either get 30 records (and I need hundreds of records) or I get Cartesian products. Can anyone provide advice to what I'm doing wrong?
Thanks in advance!
You were forgetting to link warehouses and stores by item number (plus left join is the better for this case)
Create or replace view REGION_BALANCES
as
with WAREHOUSES as
(
select
A.REGION_CODE, A.REG_DESC, A.WAREHOUSE_NUMBER,
A.FACILITY_ID, C.ITEM_NUMBER,sum(C.IN_STOCK_QTY) as IN_STOCK_QTY, B.ALLOWED_QTY
from REG_WHS_STR_ASSOC A
join ALLOWANCES B on (A.FACILITY_ID = B.FACILITY_ID)
join INVENTORIES C on (A.FACILITY_ID = FACILITY_ID) and B.ITEM_NUMBER = C.ITEM_NUMBER)
group by A.REGION_CODE,A.REG_DESC,A.WAREHOUSE_NUMBER,C.ITEM_NUMBER,B.ALLOWED_QTY
),
STORES as
(
select
A.REGION_CODE,A.REG_DESC,A.STORE_NUMBER,
A.FACILITY_ID,B.ITEM_NUMBER,sum(B.IN_STOCK_QTY) as IN_STOCK_QTY
from REG_WHS_STR_ASSOC A
join INVENTORIES B on (A.FACILITY_ID = B.FACILITY_ID)
group by A.REGION_CODE,A.REG_DESC,A.STORE_NUMBER, B.ITEM_NUMBER
)
select A.REGION_CODE, A.REG_DESC,A. WAREHOUSE_NUMBER, A.FACILITY_ID,
WAREHOUSES.ITEM_NUMBER, WAREHOUSES.IN_STOCK_QTY, WAREHOUSES.ALLOWED_QTY,
STORES.STORE_NUMBER, STORES.FACILITY_ID, STORES.ITEM_NUMBER, STORES.IN_STOCK_QTY
from REG_WHS_STR_ASSOC A
left join WAREHOUSES on (A.REGION_CODE = WAREHOUSES.REGION_CODE)
left join STORES on
(A.REGION_CODE = STORES.REGION_CODE AND STORES.ITEM_NUMBER = WAREHOUSES.ITEM_NUMBER)
order by 5,1 asc;

sql getting data three columns from one table and one from another

I have two tables sales and customers
from 1st table I want to sum two columns recived_amount and bill_amount and subtract them both and after that also want to get customer_id
from 2nd table I just want to get Customer_name
I've tried
SELECT Customer_details.CUS_name,
SUM(SALES.Bill_Amount) - SUM(SALES.Recived_Amount),
Customer_details.Cus_id
from sales
INNER JOIN Customer_details
ON Customer_details.Cus_id=sales.Cus_id
where SALES.Cus_id = 1 order BY Cus_id
SELECT Customer_details.CUS_name, (SUM(SALES.Bill_Amount) - SUM(SALES.Recived_Amount)) as Subtract,Customer_details.Cus_id
from sales INNER JOIN Customer_details ON Customer_details.Cus_id=sales.Cus_id
where SALES.Cus_id = 1
group by Customer_details.CUS_name,Customer_details.Cus_id
order BY Cus_id
SELECT Customer_details.CUS_name,
(SUM(SALES.Bill_Amount)-SUM(SALES.Recived_Amount)) AS Balance_Owed,
Customer_details.Cus_ID
FROM Sales INNER JOIN Customer_details ON Customer_details.Cus_id=Sales.Cus_id
GROUP BY Customer_details.CUS_name,Customer_details.Cus_id
ORDER BY Customer_details.Cus_id;