Joins on multiple tables to create a view [duplicate] - sql

This question already has answers here:
SQL JOIN and different types of JOINs
(6 answers)
Closed 5 years ago.
I want to create a view by joining three tables.
The schema is a bit complicated, and so for the sake of simplicity, I will mention only the tables and columns required for the problem.
There is a table sales with two columns:
SaleID(pkey),
Buyer,
Amount.
The second table is purchases with two columns:
PurchaseID(pkey),
Seller,
Amount.
I have a third table stockhistory which keeps track of the flow of materials.
The schema of that table is:
Date,
PurchaseID(fkey to column PurchaseID, Purchases Table),
SalesID(fkey to column SalesID, Sales Table),
Amount(calculated amount inserted here).
Now, each of the stockhistory records corresponds to either a record of Purchases table or Sales table, but not both or none.
I have a constraint for that purpose:
([salesid] IS NULL AND [purchaseid] IS NOT NULL OR [salesid] IS NOT NULL AND
[purchaseid] IS NULL)
Now, in the view StockReport, I am trying to pull all records from stockhistory table, and want to display the name of buyer or seller as is the case.
I have tried to write a SQL of the lines of:
SELECT StockHistory.date
, StockHistory.purchaseid
, StockHistory.salesid
, Purchases.seller
, Sales.buyer
WHERE StockHistory.purchaseid = Purchases.purchaseid
OR StockHistory.salesid = Sales.salesid
How can I do the same with LEFT JOIN?

You can use following query
SELECT
SH.date,
SH.purchaseid,
SH.salesid,
P.seller,
S.buyer
FROM stockhistory SH
LEFT JOIN Purchases P on P.PurchaseID=SH.PurchaseID
LEFT JOIN Sales S on S.salesid=SH.salesid

Related

SQL Join Table A Column A to Table B Column A or B

I have 2 tables - A Spend Table and a Sales Table
Spend Table Schema:
Spend_ID,
Spend_amount
Sales Table Schema:
Sales_ID_A,
Sales_ID_B,
Sales_amount
I want to do a left join of the spend table to the sales table. The join key from the spend table is the Spend_ID and i want to join when it matches the value in either Sales_ID_A or Sales_ID_B i.e. my match key on the sales table is in 2 columns. So in a way its like applying an 'or' condition to the join on the sales table Sales_ID_A or Sales_ID_B. If a match is found in Sales_ID_A, then no need to check Sales_ID_B. Only check Sales_ID_B if no match is found in Sales_ID_A. How do i achieve this with SQL?
Sample Data Illustration:
See screenshot
The columns called sales_id_a and sales_id_b are actually spend IDs and should better be called spend_id_a and spend_id_b.
You want to join on the first ID, but if that is null, you want to join on the second ID. Use COALESCE for this:
select *
from sales
left join spend on spend.spend_id = coalesce(sales.sales_id_a, sales.sales_id_b)

Outputting the data from several sql tables without having a common value

I have a select query which combined several tables. PRODUCTION_ORDER_RESULTS, PRODUCTION_ORDERS and SERVICE_GUARANTY_NEW have common value however STOCKS table does not.
SELECT PR_ORDERS.ARRIVED_CITY,
PR_ORDERS.MONTAJ_DATE,
PR_ORDER_RESULT.TRANSFER_DATE,
PR_ORDERS.P_ORDER_ID,
PR_ORDER_RESULT.P_ORDER_ID,
SG.SALE_CONSUMER_ID,
SG.IS_SERI_SONU,
S.BRAND_ID,
S.PROPERTY
FROM workcube_test_1.PRODUCTION_ORDER_RESULTS PR_ORDER_RESULT,
workcube_test_1.PRODUCTION_ORDERS PR_ORDERS,
workcube_test_1.SERVICE_GUARANTY_NEW SG,
workcube_test_1.STOCKS S
WHERE PR_ORDER_RESULT.P_ORDER_ID = PR_ORDERS.P_ORDER_ID
AND PR_ORDER_RESULT.PR_ORDER_ID = SG.PROCESS_ID
when I run the query, it shows the output as below.
The problem here is there are four data rows returned from PRODUCTION_ORDER_RESULTS, PRODUCTION_ORDERS, SERVICE_GUARANTY_NEW and once I have added the STOCKS table, arrived_city, montaj_date, transfer_date columns are side by side with STOCKS table's rows, but the columns value should be null, not filled with data.
The way I tried is UNION of STOCKS table, however unioned table values are ignored, can not use them in html blocks.
there needs to be at least one more join condition among tables where there's for STOCKS table, I think there might exist such a column STOCK_ID within a table such as PRODUCTION_ORDER_RESULTS in order to join with STOCKS table. I think this should be the reason for multiple returning rows. If there's no common column, then the returning data will be produced as many as the number of records within STOCK table due to existing CROSS JOIN logic within the current query. So rearrange your query as
SELECT PR_ORDERS.ARRIVED_CITY,
PR_ORDERS.MONTAJ_DATE,
PR_ORDER_RESULT.TRANSFER_DATE,
PR_ORDERS.P_ORDER_ID,
PR_ORDER_RESULT.P_ORDER_ID,
SG.SALE_CONSUMER_ID,
SG.IS_SERI_SONU,
S.BRAND_ID,
S.PROPERTY
FROM workcube_test_1.PRODUCTION_ORDER_RESULTS PR_ORDER_RESULT
JOIN workcube_test_1.PRODUCTION_ORDERS PR_ORDERS
ON PR_ORDER_RESULT.P_ORDER_ID = PR_ORDERS.P_ORDER_ID
JOIN workcube_test_1.SERVICE_GUARANTY_NEW SG
ON PR_ORDER_RESULT.PR_ORDER_ID = SG.PROCESS_ID
JOIN workcube_test_1.STOCKS S
ON PR_ORDER_RESULT.STOCK_ID = S.ID

Join 2 tables based on column name present in a table row

I have a table called Target where I have 5 columns:
ProductLevel
ProductName
CustomerLevel
CustomerName
Target
In another table called Products I have 3 columns:
ProductId
ProductCategory
ProductBrand
In the 3rd table called Customer I have 3 columns:
CustomerID
CustomerName
SubCustomerName
Is there a way to do a dynamic join where I select the column I will use in the JOIN based on the value that I have in the 1st table?
Example: If in the first table I have Category in ProductLevel, I'll join the table product using ProductCategory field. If I have Brand, I'll join using ProductBrand... The same happens with Customer table.
PS: I'm looking for a way to create it dynamically in a way I can add new columns to that tables without changing my code, then in the future I can have ProductSegment column in Product Table and Segment as a value in ProductLevel in Target table.
Yes, like this:
SELECT * FROM
Target t
INNER JOIN
Product p
ON
(t.ProductLevel = 'Category' AND t.??? = p.ProductCategory)
OR
(t.ProductLevel = 'Brand' AND t.??? = p.ProductBrand)
You didn't say which column in Target holds your product category/brand hence the ??? in the query above. Replace ??? with something sensible
PS; you can't do as you ask in your PS, and even this structure above is an indicator that your data model is broken. You can at least put the code in for it now even if there are no rows with t.ProductLevel = 'Segment'
Don't expect this to perform well or scale.. You might be able to improve performance by doing it as a set of UNION queries rather than OR, but you may run into issues where indexes aren't used, crippling performance

Populating fact table

I've a data warehouse for sales, it has 3 dimensions [product,time,store] and a fact table [sales_fact].
Primary key of 'sales_fact' table is made up of all primary keys of dimensions table, dimension tables are all filled up manually now I want to fill 'sales_fact' table with SUM of prices of products stored in a city for a specific month or 3 month period.
How should I sum up prices from product table which are related to a specific month and add it to fact table?
Considering that sum up prices from product table which are related to a specific month
is a measure, your query can be like below :
SELECT DS.City, DT.[Month], SUM(DP.Price)FROM
SalesFact AS S
LEFT JOIN DimProduct AS DP ON DP.ProductSK=S.ProductSK
LEFT JOIN DimTime AS DT ON DT.DateSK=S.DateSK
LEFT JOIN DimStore AS DS ON DS.StoreSK=S.StoreSK
WHERE [Date condition] --Add your date conditoon
GROUP BY DS.City, DT.[Month]
You can use a view for this measure.

Joining 3 tables & inserting in a 4th table in SQL server

I am joining 3 tables - items , sales , & purchase.
And then, inserting the combined data into a 4th table FULL_DETAIL_OF_ITEMS.
ITEMS table has columns : ITEM_CD, ITEM_NM, COM_CD, SALE_RT, PURCH_RT, MRP
SALES table has columns : ITEM_CD, ITEM_NM, SALE_QTY
PURCHASE table has columns : ITEM_CD, ITEM_NM, PURCH_QTY
FULL_DETAIL_OF_ITEMS table has columns :
ITEM_CD, ITEM_NM, COM_CD, SALE_RT, PURCH_RT, MRP, SALE_QTY, PURCH_QTY
The query is:
insert into FULL_DETAIL_OF_ITEMS
SELECT
Items.Item_CD,
Items.Item_NM ,
ITEMS.COM_CD,
ITEMS.SALE_RT,
ITEMS.PURCH_RT,
ITEMS.MRP,
SALES.SALE_QTY,
PURCHASE.PURCH_QTY
FROM items
JOIN sales on ITEMS.ITEM_CD = sales.ITEM_CD
JOIN purchase on items.ITEM_CD = purchase.ITEM_CD
Items table is filled but sales & purchase tables are empty, so on executing the above query nothing happens? Why so?
At least it should insert rest of the columns from the items table into the 4th table.
It finds that in sales table - sale_qty , & in purchase table, purch_qty is empty, so it should fill null in these columns in the final table & fill rest of the columns as they are picked from item table which consists data so it should fill that.
But its not doing so?
According to the definition of JOIN, ITEM_CD in item table is not matching with the ITEM_CD column of the sales & purchase table as it is empty in both, so this is the reason.
But I want that rest of the data is inserted in the 4th table, then is there any way to do this?
You need to change those join statements to left join.
By default, a join is an "inner join", which means that only rows that exist on both sides of the join will be included. A "left join" includes all rows on the "left" side of the join.
Example:
from items
left join sales on ITEMS.ITEM_CD =sales.ITEM_CD
left join purchase on items.ITEM_CD =purchase.ITEM_CD
You can minimize your query using a select into statement which will, by default, creates a new table at run time.
select Items.Item_CD,Items.Item_NM,Items.COM_CD,Items.Mrp,Items.Purchase_RT,Items.Sale_RT,
purchase.Purchase_QTY,Sales.Sale_QTY
into full_details_of_items
from Items
inner join purchase
inner join Sales
on purchase.Item_CD=Sales.Item_CD
on items.Item_CD=purchase.Item_CD