Tough SQL problem for an amateur like me - sql

My family has several stock accounts, and I keep a table of stock values for their contents and enter current values daily. Fields are...
ACCOUNT / TICKER / QUANTITY / CLOSINGDATE/ CLOSING (current price)
To get a report of the current stock contents and most recent price, I am using this code. I add this up row by row, and get an account total (for account # 2, for example ). The table is designed this way also so I can track individual stock performance.
SELECT distinct ticker, account, closingdate, quantity, closing, (quantity*closing) as "Net"
FROM "stock values" AS S
WHERE
(account=2) and
(quantity>0.000001) and
(closingdate =(SELECT MAX(closingdate) FROM "stock values" WHERE ( ticker = S.ticker) and (account=s.account)) )
But now what I would like to do is create a report that looks like this on a TdbGrid so that... i get a report, grouped by account with the most recent distinct tickers added up FOR THAT ACCOUNT. Four days later, I cannot crack this.
Account Value
1 35,000.00
2 122,132,32
3 43.23
I'm using Nexus 3 on Delphi 7.
Any help, greatly GREATLY appreciated.
Larry

To me, it looks like you just have to add a group by:
select account
, sum(quantity*closing)
from "stock_values" as S
where s.closingdate =
(
select max(closingdate)
from "stock values" as S2
where S2.ticker = S.ticker
and S2.account = S1.account
)
group by
account

Since you can have the same stock across multiple accounts, I would pre-query the last closing date per stock per account... This way, if you have stock in company "X" and entered its daily balance for Feb 4th to Account #1, but forgot to enter the "X" price for Account #5, you would have each account with different "Last Date Entered" for a particular stock. It would actually be better to have two tables... one with nothing but your stocks, closing date and closing price. Then join that to the accounts that use those stocks... However, this query should get you a DETAILED breakdown per account showing all the maximum respective stock dates... The next query will be simplified for totals per account... This one is primarily for a sanity check to ensure you're getting what you expect. This does ALL the accounts, but you can adjust your WHERE clause to get only ONE specific account if you so need to.
SELECT
ticker,
account,
closingdate,
quantity,
closing,
(quantity*closing) as "Net"
FROM
"stock values" AS S,
( select account,
ticker,
max(closingdate) LastDatePerStock
from
"stock values" sMax
group by
account, ticker ) TickerDate
WHERE
s.account = TickerDate.account
and s.ticker = TickerDate.ticker
and s.closingdate = TickerDate.LastDatePerStock
and (quantity>0.000001)
order by
account,
ticker
Now, the query simplified with just the account and the closing balance for all their stocks without seeing exactly what stocks are in the portfolio.
SELECT
account,
max( closingdate ) LatestClosingDate,
sum((quantity*closing)) as "Net"
FROM
"stock values" AS S,
( select account,
ticker,
max(closingdate) LastDatePerStock
from
"stock values" sMax
group by
account, ticker ) TickerDate
WHERE
s.account = TickerDate.account
and s.ticker = TickerDate.ticker
and s.closingdate = TickerDate.LastDatePerStock
and (quantity>0.000001)
group by
account

Related

How to group on an aggregated data

so I've to gather the data from the table such that
1.Group each order by shipment type.
2.Filter orders for which sum of sales at shipping group level is less than $35 however overall sales is greater than $35.
For eg: If an order has two shipping groups: S2H and SDD.
Then:
S2H = $20
SDD = $25
Order total = $45
In the above example the individual shipment total is less than $35, however order total is greater than $35.
I've tried till here and would like to know how can I move forward from here to get the desirable date:
SELECT
(CASE WHEN Sales > 35 AND Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Above_SDD_Order,
(CASE WHEN Sales <= 35 AND  Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Below_SDD_Order,
(CASE WHEN Sales > 35 AND Digital = 1 AND SDD = 1 AND BOPS = 0 AND S2H = 1 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Above_SDD_S2H_Digital_Order,
(CASE WHEN Sales <= 35 AND Digital = 1 AND SDD = 1 AND BOPS = 0 AND S2H = 1 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Below_SDD_S2H_Digital_Order,
(CASE WHEN Sales > 35 AND Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 1 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Above_S2H_SDD_Order,
(CASE WHEN Sales <= 35 AND Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 1 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Below_SDD_S2H_Order,
(CASE WHEN Sales > 35 AND Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 1 THEN order_no
      ELSE NULL END) AS Above_Preorder_SDD_Order,
(CASE WHEN Sales <= 35 AND Digital = 0 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 1 THEN order_no
      ELSE NULL END) AS Below_Preorder_SDD_Order,
(CASE WHEN Sales <= 35 AND Digital = 1 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Below_Digital_SDD_Order,
(CASE WHEN Sales > 35 AND Digital = 1 AND SDD = 1 AND BOPS = 0 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END )AS Above_Digital_SDD_Order,
(CASE WHEN Sales <= 35 AND Digital = 0 AND SDD = 1 AND BOPS = 1 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Below_BOPS_SDD_Order,
(CASE WHEN Sales > 35 AND Digital = 0 AND SDD = 1 AND BOPS = 1 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END) AS Above_BOPS_SDD_Order,
(CASE WHEN Sales <= 35 AND Digital = 1 AND SDD = 1 AND BOPS = 1 AND S2H = 0 AND PREORDER = 0 THEN order_no
      ELSE NULL END )AS Below_Digital_BOPS_SDD_Order,
(CASE WHEN Sales > 35 AND Digital = 1 AND SDD = 1 AND BOPS = 1 AND S2H = 0 AND PREORDER = 0 THEN order_no ELSE NULL END )AS Above_Digital_BOPS_SDD_Order
FROM 
(SELECT order_no,
MAX(CASE WHEN (Shipping_Group = 'DIGITAL_GIFT_CARD' OR Shipping_Group = 'DIGITAL' OR Shipping_Group = 'GAME_INFORMER_DIGITAL' OR Shipping_Group = 'LOYALTY') THEN 1 ELSE 0 END ) AS Digital,
MAX(CASE WHEN Shipping_Group = 'GAME_INFORMER_PHYSICAL' OR Shipping_Group = 'PHYSICAL' THEN 1 ELSE 0 END) AS S2H,
MAX(CASE WHEN Shipping_Group = 'PHYSICAL_PREORDER' OR Shipping_Group = 'DIGITAL_PREORDER' OR Shipping_Group = 'PICKUP_PREORDER' THEN 1 ELSE 0 END ) AS Preorder,    
MAX(CASE WHEN Shipping_Group = 'PICKUP' THEN 1 ELSE 0 END ) AS BOPS,
MAX(CASE WHEN Shipping_Group = 'SDD' THEN 1 ELSE 0 END) AS SDD,
SUM(pl_net_price) as Sales
From 
(SELECT order_no, Shipping_Group,pl_net_price
FROM 
eim-prod.EDW_VIEWS.ORDER_SUBMIT_PRODUCT_LINEITEM 
)
group by 1)
group by 1,2,3,4,5,6,7,8,9,10,11,12,13,14;
You can also tell me if my approach is wrong and how I should take it further as I am a newbie with SQL. Thanks

Access - return field based on criteria for a different field

I currently have a query that tells me the date of someone's last donation:
Max(Donations.DonationDate) AS MaxDate
I want to know the amount of that donation (Donations.DonationAmount).
I can get my query to show amounts for all donations, or I can get it to show me the amount of the maximum donation, but I don't know how to get it to show me the amount of the donation associated with MaxDate.
I'm not what terms to search for - I think I want something that will basically say "for MaxDate, return DonationAmount," but I'm not sure how to say that in SQL.
Image of two rows of test data
If someone gave $500 on 2/2/2020 and $100 on 3/5/2020, I want to see their last donation (MaxDate). The code below correctly returns 3/5. But then I also want to see the amount of that donation on 3/5/2020 ($100).
I've figured out how to see all the amounts ($500 and $100) and how to see the maximum amount ($500), but I don't know how to figure out the value for the MaxDate's amount.
The full code:
SELECT Nz(ContactHouseholds.HouseholdName, "ACCT:" & Donations.AccountName & " CONTACT:" & Donations.ContactName) AS HsName
,Max(Donations.DonationDate) AS MaxDate
,Households.HouseholdAddressEtc
FROM (
Donations LEFT JOIN ContactHouseholds ON Donations.ContactName = ContactHouseholds.ContactName
)
INNER JOIN Households ON Donations.HouseholdName = Households.HouseholdName
GROUP BY Nz(ContactHouseholds.HouseholdName, "ACCT:" & Donations.AccountName & " CONTACT:" & Donations.ContactName)
,Households.HouseholdAddressEtc

3 Tables into dropdown list

I have 3 tables, Clients, Products, Transactions.
When we enter a product, it is given a PID (product id) and a CID (client ID), which relate to the Clients and Transaction tables. The transaction table has a CID and Quantity.
I am trying to list all unique products and quantities, some clients have 2 listings of the same product, so if 1 is 10 units and the other is 20, then that client has 30 of product a.
The transactions table lists all sales, which are subtracted from the total.
I need the query to show the product name, client name, quantity available.
Here is the code I have so far, apologies for the mess and thanks much for any help.
This is an Access database.
SELECT Min(Products.PID) exPID,
Min(Products.[Product Name]) AS exProdName,
Min(Products.[Seller Asking]) AS exAsking,
Min(Products.CID) AS exClientID,
Min(Transactions.[CID Seller]) AS exSellerID,
Sum(Products.Quantity - ((SELECT Transactions.[No Units], Clients.Name,
Transactions.[CID Seller], Products.CID
FROM Transactions, Clients, Products
WHERE Transactions[CID Seller]=Products.CID)
) AS exSumofTrans),
Min(Clients.Name) AS exClientName,
Min(Transactions.[CID Seller]) AS exSeller
FROM Transactions, Clients, Products
WHERE (((Transactions.[CID Seller])=[Products].[CID]
AND (Products.[PID])=([Transactions].[PID])));
First issue here is an error on the inner select.
The error says:
'Syntax error in query expression (Sum(Products.Quantity-((Select Transactions.[No Units], Clients.Name, Transactions.[CID Seller], Products.CID
FROM Transactions, Clients, Products
Where Transactions[CID Seller]=Products.CID)) as exSumofTrans)'.
I had to do some guessing based on what it looks like you are trying to do and I have no way of testing it so it may need further tweaking but this will get you on the right path:
SELECT Products.PID AS exPID,
FIRST(Products.[Product Name]) AS exProdName,
FIRST(Products.[Seller Asking]) AS exAsking,
FIRST(Products.CID) AS exClientID,
SUM(Products.Quantity)-FIRST(T.exNoUnits) AS exSumofTrans,
T.exSellerID,
FIRST(Clients.Name) AS exClientName
FROM (Products
INNER JOIN (SELECT [CID Seller] AS exSellerID, PID, SUM([No Units]) AS exNoUnits
FROM Transactions GROUP BY [CID Seller], PID) AS T
ON T.PID=Products.PID)
INNER JOIN Clients ON T.exSellerID=Clients.CID
GROUP BY Products.PID, T.exSellerID

Find from every record in table one the record with most recent date in table two

I have two tables in my Ms Access 2010 project: a table Sites with site information and modality they have, and a table Visits with information about the visit.
Table Sites:
SitesID, Name, City, Modality_A (yes/no), Modality_B (yes/no), Modality_C (yes/no)
Table Visits:
VisitsID, SitesID, Startdate, VisitorID, VisitTypeID, Modality (A/B/C)
I now want to get from every record in Sites
The number (count) of visits
The most recent Visits.Startdate
The corresponding VisitorID and VisitTypeID from the most recent Startdate.
When there is no Visit to a certain Site, the site still has to be on the list.
Last but not least, I want to be able to filter on Modality. So when I choose Modality A, I want only the sites with Sites.modality_A=yes and only the visits information with Modality A.
what i have so far (for Modality A):
SELECT DISTINCTROW Sites.SitesID, Sites.Name, Sites.City, Max(IIf([Visits].[Modality]="A", [Visits].[Startdate],Null)) AS MaxOfDate, Sum(IIf(Visits.Modality="A",1,0)) AS CountOfVisits, Max(IIf([Visits].[Modality]="A",[Visits].[VisitTypeID],Null)) AS MaxOfVisitTypeID, Max(IIf([Visits].[Modality]="A",[Visits].[VisitorID],Null)) AS MaxOfVisitorID
FROM Visits RIGHT JOIN Sites ON Visits.SitesID = Sites.SitesID
WHERE (((Sites.SitesID) In (select Sites.SitesID from Sites where (Sites.Modality_A=Yes))) GROUP BY Sites.SitesID, Sites.Name, Sites.City ORDER BY Max(IIf([Visits].[Modality]="A",[Visits].[Startdate],Null)) DESC;"
This works fairly well, but has two problems:
The MAX(visitorID) does not work, it gives not the visitor which did the last visit, but the visitorID with the highest number.
The MAX VisitTypeID does not work, it gives not the VisitTypeID from the last visit, but the VisitTypeID with the highest number
I can't find how to make this work. Any ideas? A complete other SQL then what I have so far is, of course, fine too :)
Thanks a lot!!
I would approach this as:
A join and group by to get the most recent date and count.
A join to get the additional information about the visitor.
A where clause for filtering on modality.
This looks like:
select sv.*, v.visitorid, v.visittypeid
from (select s.sitesId, s.name, s.modality,
count(v.visitId) as numvisits,
max(v.startdate) as maxdate
from sites as s left join
visits as v
on s.sitesid = v.sitesId
group by s.sitesId, s.name, s.modality
) as sv left join
visits as v
on v.sitesId = sv.sitesId and v.startdate = sv.maxdate
where sv.modality = "A";

Updating a field within a table based on a field within the same table

HI ALL
I wish to update a row within my table from a row within that same table,
I have a table called INVENTORY. it stores PRICES for products.
I have SALES codes and I have STOCK codes which are related.
I wish to transfer all the PRICING from the SALES codes to the STOCK codes.
I wish to do something like this:
update INVENTORY
set PRICE = (SELECT PRICE WHERE CODE = "SALES CODE EQUIVALENT OF THE STOCK CODE IM IN")
WHERE
CODE = "SOME STOCK CODE"
a SALES CODE would look like this "U_12345", its STOCK code equivalent would look like "S_12345"
thanks
You're very close, you just need to specify which table you're selecting from as part of your sub-query...
update INVENTORY
set PRICE = (SELECT PRICE FROM your_table WHERE CODE = "SALES CODE EQUIVALENT OF THE STOCK CODE IM IN")
WHERE
CODE = "SOME STOCK CODE"
Even if "your_table" is INVENTORY, you still need to specify it in there.
The only time it gets 'tricky' is when your selecting from the same table that you're update, AND when you need a value from the updated record in the SELECT statement. In that case you need to differentiate between the two references, using an alias. For example...
update INVENTORY
set PRICE = (SELECT PRICE FROM INVENTORY AS [new_price] WHERE [new_price].CODE = INVENTORY.NEW_CODE)
WHERE
CODE = "SOME STOCK CODE"
UPDATE INVENTORY
SET PRICE = i_sales.PRICE
FROM INVENTORY, INVENTORY i_sales
WHERE INVENTORY.CODE LIKE 'S\_%'
AND i_sales.CODE = REPLACE(INVENTORY.Code, 'S', 'U')
This updates prices for all 'stock' records in INVENTORY with prices from the corresponding 'sales' records.
If you would prefer to update individual prices, change WHERE to something like this:
WHERE i_stock.CODE = 'S_12345'
or this:
WHERE i_stock.CODE IN ('S_12345', 'S_12346')
Note: The FROM syntax used is based on this doc page.