Convert heavy asp code to run in sql - sql

A bit of asp code which in context does; timeline the product's sales performance based on the start year which product was online to the number of years active, for example a product published on 2000 would have the peak sales for couple of years but by 2004 there would be none...but code this is for all products in the system and grouping by year...(if you questions I can answer them or I think looking at code would give a fair idea on what it's doing !!)
Firstly it runs this query to get the data ( which I want to change ):
SELECT Products.ProductID, Products.AnticipatedSalesPattern, Convert(Char(10),Invoices.Date,103) As [date], Orders.Cost
FROM (Orders INNER JOIN Products ON Orders.ProductID = Products.ProductID)
INNER JOIN Invoices ON Orders.Invoice = Invoices.InvoiceNum
WHERE (Products.IsResource=1 AND Orders.Returned<>1 AND Orders.Cost<>0)
ORDER BY Products.ProductID, Invoices.Date;
Here is how it process the data(in asp), I know it's not effective just made it sample modeling data...
while not dbrecords.eof
RecordsCount = RecordsCount + 1
if dbrecords("ProductID") <> LastPID then
PIDsCount = PIDsCount + 1
LastPID = dbrecords("ProductID")
FirstSaleDate = dbrecords("Date")
if month(FirstSaleDate) < 9 then
FirstSchoolYear = Year(FirstSaleDate) - 1
else
FirstSchoolYear = Year(FirstSaleDate)
end if
end if
YearsSinceFirstSale = int(DateDiff("d",FirstSaleDate,dbrecords("Date"))/365)
MyArray(FirstSchoolYear-2000,YearsSinceFirstSale) = MyArray(FirstSchoolYear-2000,YearsSinceFirstSale) + dbrecords("Cost")
MyArrayTotals(FirstSchoolYear-2000) = MyArrayTotals(FirstSchoolYear-2000) + dbrecords("Cost")
TotalSales = TotalSales + dbrecords("Cost")
dbrecords.movenext
wend
Now what I like is to remove the whole process of putting the data into an array and the query to return the yearly data
What i'm curently stuck on is to write sql to pass the years since first sale and keeping track of each products (how to implement that in sql), I beleieve parameters are accepted via CTE statements...
Also if you think that this can be achieved some other way much effieciently that would be great too
Any help would be greatly appreciated...
So far I got to;
This doesn't provide with the identical data produced by the asp...and also let me know if there is a better way to do this...
DROP VIEW inline_view;
GO
CREATE VIEW inline_view AS
SELECT p2.ProductID, p2.AnticipatedSalesPattern, Invoices.Date, Orders.Cost, case when MONTH(date) < 9 then YEAR(date)-1 else YEAR(date) end as year,
(select top 1 case when MONTH(i.date) < 9 then YEAR(i.date)-1 else YEAR(i.date) end from Invoices i inner join Orders o on i.InvoiceNum=o.Invoice
inner join Products p on o.ProductID = p.ProductID where p2.ProductID = p.productID order by i.Date asc) as startsale
FROM (Orders INNER JOIN Products p2 ON Orders.ProductID = p2.ProductID)
INNER JOIN Invoices ON Orders.Invoice = Invoices.InvoiceNum
WHERE (p2.IsResource=1 AND Orders.Returned<>1 AND Orders.Cost<>0)
;
GO
SELECT * FROM (
select SUM(cost) sum, datediff(y, startsale, year) as year, startsale from inline_view
group by year, startsale
) as data
PIVOT
(
sum(sum)
--years after product is online
FOR year IN ([1], [2], [3],[4],[5],[6],[7],[8],[9], [10],[11], [12])
) as pvt;

Related

Join tables and Count participants in the past

I have participants that have multiple orders. I can easily find counts of orders in the past but have to use a join to count participants in the past. The code I am using does not give me correct numbers. The code is :
select count(distinct o.participant_id)
from dbaq.participant p, dbaq.orders o
where o.participant_id=p.participant_id and
(p.water_staff=1) and p.active = '1' and
date_part('year', o.order_date) = 2018;
I figured out why this is not going to work ... the number of active participants goes down when I look at each subsequent year in the past ... becasue they are leaving and no longer active. I don't think there is a way to track who was active in the past. Thanks for your input though - great suggestions below.
I think you want to find the number of participants for an active order in this year. Am I right? If yes you could try
SELECT o.participant_id,
COUNT(*)
FROM dbaq.participant p,
dbaq.orders o
WHERE o.participant_id = p.participant_id
AND p.water_staff = 1
AND p.active = '1'
AND extract(YEAR FROM o.order_date) = '2018'
group by o.participant_id;
Try this:
SELECT
COUNT(DISTINCT o.participant_id)
FROM
dbaq.orders o
JOIN
dbaq.participant p
ON
o.participant_id = p.participant_id
WHERE
p.water_staff = 1
AND
p.active = '1'
AND
DATE_PART('year', o.order_date) = 2018;

Query Results across 3 tables

I have a need to see a client was billed for a specific item. The tables are as follows Client, Orders, Details. The way they connect is Client to Orders and Orders to Details. (client.acctno = order.acctno, order.orderno = details.orderno)
How can I search all orders and display only those that have not been sold a specific item (sample code with exact table names below). My data keep showing all clients because they weren't sold the items a specific order I want to bunch them all together as ALL ORDERS and compare.
SELECT *
FROM plshared.dbo.client
LEFT OUTER JOIN PL00.dbo.ordhdr ON ordhdr.ACCT_NO = client.ACCT_NO
WHERE NOT EXISTS (SELECT *
FROM pl00.dbo.orddet
WHERE orddet.ORDER_NO = ordhdr.order_no
AND orddet.ITEM_NO = '2017WI')
--GROUP BY client.ACCT_NO
ORDER BY CLIENT.ACCT_NO
The problem is your query is at the order level. You might find it easier to get the clients by doing:
SELECT o.ACCT_NO
FROM PL00.dbo.ordhdr o JOIN
pl00.dbo.orddet od
ON od.ORDER_NO = o.order_no
GROUP BY o.ACCT_NO
HAVING SUM(CASE WHEN od.ITEM_NO = '2017WI' THEN 1 ELSE 0 END) = 0;
ORDER BY o.ACCT_NO;

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 Using Multiply 3 Times with different ID's

I have tables called Products and ProductsDetails. I want to get something like the price of an order. So let's say I want 5 pairs of "Headphonesv1" ( Comparing with not ID but name, since name could change ), 2 packs of "GumOrbit" and 7 packs of "crisps". Pair of headphonesv1 costs 10$, gum 1$ and crisps 2$. So the answer that I should get is bill ID, Bill date, and TotalCost which is = 66. My question is how do I make multiple calculations? The code that I've been trying with one at least but I get syntax error:
SELECT Products.billID, Products.Date, (ProductsDetails.Price * 5 WHERE ProductsDetails.name LIKE 'Headphonesv1')
FROM Products INNER JOIN ProductsDetails ON Products.billdID = ProductsDetails.billID
Also have tried inserting SELECT inside () but then the values that I get are wrong and creating one more inner join inside doesn't seem promising
I think if you just want to see that total cost for multiple items you can use a aggregate and case expression to get the SUM.
SELECT Products.billID,
Products.Date,
SUM(CASE WHEN ProductsDetails.name LIKE 'Headphonesv1' THEN ProductsDetails.Price * 5
WHEN ProductsDetails.name LIKE 'GumOrbit' THEN ProductsDetails.Price * 2
WHEN ProductsDetails.name LIKE 'crisps' THEN ProductsDetails.Price * 7
END) TotalCost
FROM Products
INNER JOIN ProductsDetails ON Products.billdID = ProductsDetails.billID
GROUP BY Products.billID,
Products.Date
this seems very hard coded to serve much use though
Your previous code has a few synax erros. you are closing your parenthesis in the wrong location, and the FROM ... clause should be before the WHERE ... clause. Change your code to this:
SELECT Products.billID, Products.Date, (ProductsDetails.Price * 5)
FROM Products INNER JOIN ProductsDetails ON Products.billdID = ProductsDetails.billID
WHERE ProductsDetails.name LIKE 'Headphonesv1'
and let me know if it works now.
Edited:
The OP requested how to obtain that information for more than one Product. In that case you could switch the statement to:
SELECT SUM(Cost)
FROM (
SELECT Products.billID, Products.Date,
(ProductsDetails.Price *
(CASE WHEN ProductsDetails.name='Headphonesv1' THEN 5 ELSE
CASE WHEN ProductsDetails.name='GumOrbit' THEN 7 ELSE 0 END
END)
) AS Cost
FROM Products INNER JOIN ProductsDetails ON Products.billdID = ProductsDetails.billID
WHERE (ProductsDetails.name = 'Headphonesv1') OR (ProductsDetails.name = 'GumOrbit')
)
And you can continue to add more products.
You probably have another two tables: cart(cartID int/*,more info*/) and cartItems(cartID int /*FK*/, item varchar(50),qty int) where you add something. Finally,
select sum(pd.price * ci.qty) tot
FROM Products p
INNER JOIN ProductsDetails pd ON p.billdID = pd.billID
inner join cartItems ci on ci.item = pd.name
inner join cart c on c.cartID = ci.cartID
where c.cartID = 123456

Group on two columns and calculate net total SQL Query

I am finding it difficult to modify an existing SQL query to group records on two columns. Following is the query which retrieves records from multiple tables by joining:
SELECT
InM.invm_No AS DocNo,
InM.docs_DocCode,
D.doctyp_Desc AS DocType,
L.loc_Desc AS Site,
InM.sup_Code AS Supplier,
InD.invd_Qty,
InD.invd_Rate
FROM
[SI_InventoryMaster] InM
INNER JOIN
[SI_DocType] AS D ON InM.doctyp_Code = D.doctyp_Code
INNER JOIN
SI_Supplier S ON InM.sup_Code = S.sup_Code
INNER JOIN
[SI_InventoryDetail] AS InD ON InD.invm_No = InM.invm_No
AND InM.invm_verified = 1
AND InM.docs_DocCode = 'GRN'
AND MONTH (InM.invm_Date) = 12
AND YEAR(InM.invm_date) = 2013
INNER JOIN
SI_Location L ON InD.loc_code = L.loc_Code
ORDER BY
InM.invm_No
Which results the following:
I need to group records "by DocNo by Site" and find total amount for each site. Total amount will be last column in this resultset and it is net of product of InD.invd_Qty and InD.invd_Rate for each site.
For DocNo: 00000030, there are 4 records of CWS Store Site, so its total amount would be calculated as: 7684.999+7684.999+3000+3000=21369.998
In this particular example, modified query should return following resultset:
Please help.
Thanks.
Try grouping on all the columns associated with those two columns. Something like:
SELECT InM.invm_No AS DocNo, InM.docs_DocCode, D.doctyp_Desc AS DocType,
L.loc_Desc AS Site, InM.sup_Code AS Supplier,
sum(InD.invd_Qty),
sum(InD.invd_Rate)
FROM [SI_InventoryMaster] InM INNER JOIN
[SI_DocType] AS D
ON InM.doctyp_Code = D.doctyp_Code INNER JOIN
SI_Supplier S
ON InM.sup_Code = S.sup_Code INNER JOIN
[SI_InventoryDetail] AS InD
ON InD.invm_No = InM.invm_No AND
InM.invm_verified = 1 AND
InM.docs_DocCode = 'GRN' AND
MONTH (InM.invm_Date) = 12 AND
YEAR(InM.invm_date) = 2013 INNER JOIN
SI_Location L
ON InD.loc_code = L.loc_Code
GROUP BY InM.invm_No AS DocNo, InM.docs_DocCode, D.doctyp_Desc AS DocType,
L.loc_Desc AS Site, InM.sup_Code AS Supplier;