How to convert a query into a nested query - sql

How do I change this query into a nested query?
The query and tables are listed below.
SELECT
Nation.N_NAME as "nation",
ROUND(
SUM(
Lineitem.L_QUANTITY * (Lineitem.L_EXTENDEDPRICE - Lineitem.L_DISCOUNT)
), 2
) AS "order size"
FROM Nation
JOIN Supplier ON Nation.N_NATIONKEY = Supplier.S_NATIONKEY
JOIN Customer ON Supplier.S_NATIONKEY = Customer.C_NATIONKEY
JOIN Orders ON Customer.C_CUSTKEY = Orders.O_CUSTKEY
JOIN Lineitem ON Orders.O_ORDERKEY = Lineitem.L_ORDERKEY
WHERE Lineitem.L_SUPPKEY = Supplier.S_SUPPKEY
GROUP BY Nation.N_NAME
;
tables goes as follows
Nation : N_NATIONKEY, N_NAME
Supplier : S_SUPPKEY, S_NAME, S_NATIONKEY
Customer : C_CUSTKEY, C_NAME, C_NATIONKEY
Orders: O_ORDERKEY, O_CUSTKEY
Lineitem: L_ORDERKEY, L_SUPPKEY, L_QUANTITY, L_EXTENDEDPRICE, L_DISCOUNT

I'm not sure exactly what kind of nested join you're looking for, but here is one option:
SELECT
src.N_NAME as "nation",
ROUND(
SUM(
lineitem.L_QUANTITY * (lineitem.L_EXTENDEDPRICE - lineitem.L_DISCOUNT)
), 2
) AS "order size"
FROM lineitem -- Get line items
INNER JOIN (
SELECT nation.N_NAME, supplier.S_SUPPKEY, Orders.O_ORDERKEY
FROM nation
JOIN Supplier ON Nation.N_NATIONKEY = Supplier.S_NATIONKEY
JOIN Customer ON Supplier.S_NATIONKEY = Customer.C_NATIONKEY
JOIN Orders ON Customer.C_CUSTKEY = Orders.O_CUSTKEY
) src ON lineitem.L_SUPPKEY = src.S_SUPPKEY AND lineitem.L_ORDERKEY = src.O_ORDERKEY
GROUP BY src.N_NAME
I haven't tested it but give it a try and see if it works. If it doesn't give you what you want, please post some sample data.

Related

Exclude those orders which has service code 'AAAA'

An order can have multiple services. As per the functionality, I have to remove those orders from the selection which have a service code 'AAAA'.
I mean if an order has two services code 'AAAA' and 'AAAB'. Then this must not be included in the output because this order has a Service code 'AAAA'. Please see the screenshot below for more info.
Query:
Select BO.OrderID ,OrderDate ,BackgroundServiceID , BST.BST_Name ,BST_Code from
BackgroundOrder BO
JOIN BackgroundOrderService BOS ON BO.OrderID = BOS.OrderID
JOIN ams.lkpBkgSvcType BST ON BST.BST_ID = BOS.BackgroundServiceID
Expected Output Query:
Select BO.OrderID ,OrderDate ,BackgroundServiceID , BST.BST_Name ,BST_Code from
BackgroundOrder BO
JOIN BackgroundOrderService BOS ON BO.OrderID = BOS.OrderID
JOIN ams.lkpBkgSvcType BST ON BST.BST_ID = BOS.BackgroundServiceID
Where BST.BST_Code = 'AAAB' AND BO.OrderID not in
(Select BO.OrderID from
BackgroundOrder BO
JOIN BackgroundOrderService BOS ON BO.OrderID = BOS.OrderID
JOIN ams.lkpBkgSvcType BST ON BST.BST_ID = BOS.BackgroundServiceID
Where BST.BST_Code = 'AAAA'
)
Please suggest some other ways to get the above output without using a not-in statement.
You can wrap your query in a cte and count the occurences of 'AAAA' per OrderId then filter where it's zero
with t as (
select BO.OrderID, OrderDate, BackgroundServiceID, BST.BST_Name, BST_Code,
Sum(case when bst_code='AAAA' then 1 else 0 end) over(partition by BO.OrderID) cnt=0
from BackgroundOrder BO
join BackgroundOrderService BOS on BOS.OrderID = BO.OrderID
join ams.lkpBkgSvcType BST on BST.BST_ID = BOS.BackgroundServiceID
)
select OrderID, OrderDate, BackgroundServiceID, BST_Name, BST_Code
from t
where cnt=0

How to improve SELECT statements with multiple sub-queries

How can I better improve the following SQL statements? I have tried using EXCEPT but it does not work. Any suggestions/advice are greatly welcome!
SELECT COUNT(*)
FROM ( SELECT L_ORDERKEY, COUNT(*)
FROM LINEITEM
GROUP BY L_ORDERKEY
HAVING COUNT(*) > (SELECT DISTINCT TSIZE
FROM LINEITEM) );
SELECT LINEITEM.L_ORDERKEY, LINEITEM.L_LINENUMBER
FROM LINEITEM JOIN PART
ON LINEITEM.L_PARTKEY = PART.P_PARTKEY
WHERE PART.P_PARTKEY IN (46557,20193,19110,45690,45123)
MINUS
(SELECT LINEITEM.L_ORDERKEY, LINEITEM.L_LINENUMBER
FROM LINEITEM JOIN PART
ON LINEITEM.L_PARTKEY = PART.P_PARTKEY
WHERE PART.P_PARTKEY IN (46557,20193,19110,45690,45123)
MINUS
SELECT LINEITEM.L_ORDERKEY, LINEITEM.L_LINENUMBER
FROM LINEITEM JOIN SUPPLIER
ON LINEITEM.L_SUPPKEY = SUPPLIER.S_SUPPKEY
WHERE SUPPLIER.S_SUPPKEY IN (4567,2323,1987,2194,1111)
);
You can use not exists for the second query
SELECT L.L_ORDERKEY, L.L_LINENUMBER
FROM LINEITEM L
JOIN PART P
ON L.L_PARTKEY = P.P_PARTKEY
WHERE P.P_PARTKEY IN (46557, 20193, 19110, 45690, 45123)
AND NOT EXISTS
(SELECT 0
FROM SUPPLIER S
WHERE S.S_SUPPKEY IN (4567, 2323, 1987, 2194, 1111)
AND L.L_SUPPKEY = S.S_SUPPKEY );

Sql Joining 3 Tables Query for Loan Total Result

I have to get the total of Customer Loan from 3 tables the two tables are given loan to sum and the other subtract the paid amount and the tables have Customer ID in common. so far I can get the result only if the Customer ID exist in all tables but if it doesn't exist in one table I won't get Customer in my result. or I get NULL customer IDs when I anchor to the customer.
SELECT
AS1.C_ID AS [Customer ID],
ISNULL(AS1.OldCustomerLoan, 0) AS [Old Loan],
ISNULL(AS2.NewGivenLoan, 0) AS [New Given Loan],
ISNULL(AS3.LoanPaid, 0) AS [PaidLoanAmount],
(ISNULL(AS1.OldCustomerLoan, 0) +
ISNULL(AS2.NewGivenLoan, 0) -
ISNULL(AS3.LoanPaid,0) ) AS Total
FROM
Customer C
LEFT OUTER JOIN
(SELECT
MOC.C_ID,
SUM(MOC.Quantity) AS OldCustomerLoan
FROM
Money_On_Customer MOC (NOLOCK)
GROUP BY
MOC.C_ID) AS1
ON c.C_Id = AS1.C_Id
LEFT OUTER JOIN
(SELECT
NGL.C_ID
,SUM(NGL.G_Take_Loan) AS NewGivenLoan
FROM
Given_Loan NGL
GROUP BY
NGL.C_ID) AS2
ON c.C_Id = AS2.C_Id
LEFT OUTER JOIN
(SELECT
GLP.C_ID, SUM(GLP.G_P_Loan) AS LoanPaid
FROM
Given_Loan_Paid GLP
GROUP BY
GLP.C_ID ) AS3
ON c.C_Id = AS3.C_Id
Here Is a picture of my two results:
When I get NULL Customer IDs
When I don't get All the Customers
You need to use c.c_id for the first column
In order to only get records where they exist in at least one of the tables you can add this to you query, just put you current query in place of the dots, and add the leftid col
Select *
From
(Select c.c_id custonerid,
Coalesce(Coalesce(as1.c_id,as2.c_id),as3.c_id) leftid,......
From ....
) ilv
Where leftid is not null
You might be able to just add
Where coalesce(coalesce(as1.c_id,as2.c_id),as3.c_id) is not null
To then end of your query
#Ab Bennett's answer is right,
because you should use your main(master) table's primary key column
if Customer ID is not available in as1 (Money_On_Customer) it will show null.
Hope you understand my explanation.
UPDATE:
and use following for getting customer id
COALESCE(c.C_Id, AS1.C_Id, AS2.C_Id)
you will get first not null Customer ID
Here is My answer with the help of #Ab Bennett
Select *
From
(
SELECT
C.C_Name AS [Customer ID],
ISNULL(AS1.OldCustomerLoan, 0) AS [Old Loan],
ISNULL(AS2.NewGivenLoan, 0) AS [New Given Loan],
ISNULL(AS3.LoanPaid, 0) AS [PaidLoanAmount],
(ISNULL(AS1.OldCustomerLoan, 0) +
ISNULL(AS2.NewGivenLoan, 0) -
ISNULL(AS3.LoanPaid,0) ) AS Total
FROM
Customer C
LEFT OUTER JOIN
(SELECT
MOC.C_ID,
SUM(MOC.Quantity) AS OldCustomerLoan
FROM
Money_On_Customer MOC (NOLOCK)
GROUP BY
MOC.C_ID) AS1
ON c.C_Id = AS1.C_Id
LEFT OUTER JOIN
(SELECT
NGL.C_ID
,SUM(NGL.G_Take_Loan) AS NewGivenLoan
FROM
Given_Loan NGL
GROUP BY
NGL.C_ID) AS2
ON c.C_Id = AS2.C_Id
LEFT OUTER JOIN
(SELECT
GLP.C_ID, SUM(GLP.G_P_Loan) AS LoanPaid
FROM
Given_Loan_Paid GLP
GROUP BY
GLP.C_ID ) AS3
ON c.C_Id = AS3.C_Id) ilv
Where not ([Old Loan] = 0 and [New Given Loan]=0 and PaidLoanAmount =0 )

SQL - Only show results for one column in first instance of a duplicated record

I am finding it difficult to explain exactly what I am trying to achieve so I think it best to show a visual representation.
Example of how my query results currently look
Example of how I want the results to look
The report I am running shows a list of every product within orders. Each product has its own cost assigned to it. Another column is a delivery charge, but this is a charge assigned to the order; not individual products. I want to be able to show the delivery charge against the first product in each order ONLY.
I have attempted, for far too long, to try and find an answer to this query but have had no luck. I don't know if it is even possible so assistance of any sort, or even just being pointed in the right direction, would be of great help.
Thanks
EDIT.
If it helps here is my query:
SELECT dbo.Orders.EncryptedOrderId,
dbo.OrderProduct.ProductID,
dbo.OrderProduct.QuantityPerRecipient,
dbo.OrderProduct.NumRecipients,
dbo.OrderProduct.TotalQuantity,
dbo.DocType.Name AS [Product Type],
dbo.ProductGroup_Culture.Name AS [Product Group],
RIGHT(CatalogNo, CHARINDEX('_', REVERSE('_' + CatalogNo)) -1) AS [HamptonsType],
FORMAT(dbo.Orders.DateOrderCreated, 'dd/MM/yyyy HH:mm:ss') AS 'DateOrderCreated',
CAST(REPLACE(dbo.Orders.ClearingResult, 'utf-8', 'utf-16') AS XML ).value('(/UserData//CostCenter/node())[1]', 'nvarchar(max)') AS [Cost Center],
dbo.Users.FirstName,
dbo.Users.LastName,
dbo.Users.CompanyName AS [Branch Name],
dbo.Users.Department AS Subsidiary,
dbo.Users.Custom1,
dbo.Users.Custom2,
dbo.Users.Custom3,
dbo.Users.Custom4,
dbo.Users.Custom5,
dbo.OrderProduct.TotalPrice,
dbo.Orders.ShippingCharges,
dbo.OrderProduct.OrderProductID,
dbo.FileSubmissionDocument.OriginalFileType,
COALESCE (dbo.FileSubmissionDocument.Title, dbo.Product_Culture.Name) AS [Product Name],
OPDV.FriendlyValue AS 'BCard Recipient'
FROM dbo.DocType
INNER JOIN dbo.Doc
ON dbo.DocType.DocTypeID = dbo.Doc.DocTypeID
INNER JOIN dbo.OrderProduct
ON dbo.Doc.ProductID = dbo.OrderProduct.ProductID
LEFT JOIN dbo.Product
ON dbo.Product.ProductID = dbo.Doc.ProductID
LEFT JOIN dbo.ProductGroupMembership
ON dbo.ProductGroupMembership.ProductID = dbo.Doc.ProductID
LEFT JOIN dbo.ProductGroup_Culture
ON dbo.ProductGroup_Culture.ProductGroupID = dbo.ProductGroupMembership.ProductGroupID
INNER JOIN dbo.Orders
ON dbo.OrderProduct.OrderID = dbo.Orders.OrderID
INNER JOIN dbo.Users
ON dbo.Orders.UserID = dbo.Users.UserID
INNER JOIN dbo.Product_Culture
ON dbo.OrderProduct.ProductID = dbo.Product_Culture.ProductID
INNER JOIN dbo.Store_Culture
ON dbo.Store_Culture.StoreID = dbo.Users.AssignedToStoreID FULL OUTER
JOIN dbo.FileSubmissionDocument
ON dbo.OrderProduct.OrderProductID = dbo.FileSubmissionDocument.SubOrderProductID - 1
LEFT JOIN (SELECT OP.OrderProductID,
OP.DialID,
OP.FriendlyValue
FROM OrderProductDialValue OP
LEFT JOIN Dial DI ON DI.DialID = OP.DialID
LEFT JOIN OrderProduct OT ON OT.OrderProductID = OP.OrderProductID
LEFT JOIN Product PR ON PR.ProductID = OT.ProductID
WHERE PR.ExternalID = 'BCName'
AND DI.UProduceDialName = 'Name') OPDV ON OPDV.OrderProductID = dbo.OrderProduct.OrderProductID
WHERE ('#CUSTOMERNAME' is null
OR '#CUSTOMERNAME' = ''
OR dbo.Store_Culture.Name LIKE '%' + '#CUSTOMERNAME' + '%')
AND dbo.OrderProduct.IsDraft = 0
AND dbo.Orders.IsCart=0
AND dbo.Orders.IsSaveForLater=0
AND (('#DATE' <= dbo.Orders.DateOrderCreated)
OR ('#DATE' IS NULL)
OR ('#DATE'=''))
AND ((DATEADD(day, 1, '#DATE') >= dbo.Orders.DateOrderCreated)
OR ('#DATE' IS NULL)
OR ('#DATE'=''))
AND dbo.Users.LastName NOT LIKE '%TEST%'
ORDER BY dbo.Orders.OrderID DESC, dbo.OrderProduct.OrderProductID DESC
The query runs through a reporting system on an online portal so the values that show as #CUSTOMERNAME or #DATE are variables based on values given at the time when the report is run.
this may help you
select orderid,
productid,
productvalue,
case ROW_NUMBER() over (partition by orderid order by orderid)
when 1 then deliverycharge
else null end as 'deliverycharge'
from ........
I assume your query looks like
select orderID
, productID
, productValue
, DeliveryCharge
from test_t
order by orderID
, productValue desc
;
and that you want delivery charges listed for the most expensive product of each order.
If supported by your rdbms, you can use the analytic RANK function
select orderID
, productID
, productValue
, DeliveryCharge
, CASE RANK() OVER ( PARTITION BY orderID ORDER BY productValue DESC ) WHEN 1 THEN DeliveryCharge ELSE NULL END r
from test_t
order by orderID
, productValue desc
;
If your rdbms does not support RANK, you can emulate it using a left join with a suitably aggregated copy of your table:
select t.orderID
, t.productID
, t.productValue
, rt.mdc DeliveryCharge
from test_t t
left join (
select orderID
, max(productValue) mp
, max(DeliveryCharge) mdc
from test_t
group by orderID
) rt
on (
rt.orderID = t.orderID
AND rt.mp = t.productValue
)
order by orderID
, productValue desc
;
The tacit assumption is that the delivery charge is by order (which seems reasonable as you wouldn't want to selectively drop it otherwise, right ?).
Moreover, both solutions will produce multiple rows containing the delivery charge per order if that order contains multipleproducts with the same productValue.
Tested on oracle 12c1;

SQL Multiple JOIN Query Not successful

Background
I have three tables: Stock, PurchaseEntry, and SalesEntry.
These tables have the fields ProductName, MRP, LandinPrice and Qty in common.
I need to join these tables in order to get SUM(Qty) in PurchaseEntry and SalesEntry with the same ProductName, MRP, and LandinPrice as Stock.
Problem
I tried using the following query, but the result was not as I desired.
SUM(Qty) of PurchaseEntry Gives some random results, whereas SUM(Qty) of SalesEntry is correct.
But when I use JOIN on PurchaseEntry alone individually, I get the correct values.
Question
How I can get the proper results, and what type of JOINs should be used?
SQL Code
SELECT Stock.ProductName,
Stock.MRP,
Stock.LandinPrice,
SUM(PurchaseEntry.TotalQty)
AS PurchaseQty,
SUM(SalesEntry.Qty)
AS SalesQty
FROM Stock
JOIN PurchaseEntry
ON Stock.ProductName = PurchaseEntry.ProductName
AND Stock.MRP = PurchaseEntry.MRP
AND Stock.LandinPrice = PurchaseEntry.LandinPrice
JOIN SalesEntry
ON Stock.ProductName = SalesEntry.ProductName
AND Stock.MRP = SalesEntry.MRPPrice
AND Stock.LandinPrice = SalesEntry.LandingAmt
GROUP BY Stock.ProductName,
Stock.MRP,
Stock.LandinPrice
Solved:
I tried changing the Query myself. And I got the proper Output that i required. Below is that Query.
SELECT Stock.ProductName,
Stock.MRP,Stock.LandinPrice,
(SELECT SUM(PurchaseEntry.TotalQty)
FROM PurchaseEntry
WHERE Stock.ProductName=PurchaseEntry.ProductName
AND Stock.MRP=PurchaseEntry.MRP
AND Stock.LandinPrice=PurchaseEntry.LandinPrice) AS PurchaseQty,
(SELECT SUM(SalesEntry.Qty)
FROM SalesEntry
WHERE SalesEntry.ProductName=Stock.ProductName
AND SalesEntry.MRPPrice=Stock.MRP
AND SalesEntry.LandingAmt= Stock.LandinPrice ) AS SalesQty
FROM Stock
GROUP BY Stock.ProductName,Stock.MRP,Stock.LandinPrice
You might try something like
SELECT Stock.ProductName,Stock.MRP,Stock.LandinPrice,
(SELECT SUM(PurchaseEntry.TotalQty)
FROM PurchaseEntry
WHERE PurchaseEntry.ProductName=Stock.ProductName
AND PurchaseEntry.MRP=Stock.MRP
AND PurchaseEntry.LandinPrice=Stock.LandinPrice) AS PurchaseQty
(SELECT SUM(SalesEntry.Qty)
FROM SalesEntry
WHERE SalesEntry.ProductName=Stock.ProductName
AND SalesEntry.MRPPrice=Stock.MRP
AND SalesEntry.LandingAmt=Stock.LandinPrice) AS SalesQty
FROM Stock
Your existing query would have PurchaseQty multiplied by the number of sales and SalesQty multiplied by the number of purchases. Of course I'm assuming that the combination of stock ProductName, MRP, and LandinPrice are unique.
SELECT
Stock.ProductName,
Stock.MRP,
Stock.LandinPrice,
SUM(PurchaseEntry.TotalQty) AS PurchaseQty,
Sales.SalesQty
FROM
Stock
INNER JOIN PurchaseEntry ON Stock.ProductName = PurchaseEntry.ProductName AND Stock.MRP = PurchaseEntry.MRP
AND Stock.LandinPrice = PurchaseEntry.LandinPrice
INNER JOIN
(
SELECT SUM(SE.Qty) AS 'SalesQty', SE.ProductName, SE.LandingAmt, SE.MRPPrice
FROM SalesEntry SE INNER JOIN
Stock S ON S.LandinPrice = SE.LandingAmt AND S.MRP = SE.MRPPrice AND S.ProductName = SE.ProductName
GROUP BY SE.ProductName, SE.LandingAmt, SE.MRPPrice
) Sales ON Sales.ProductName = Stock.ProductName AND Sales.LandingAmt = Stock.LandinPrice
AND Sales.MRPPrice = Stock.MRP
GROUP BY
Stock.ProductName,
Stock.MRP,
Stock.LandinPrice