I'm working with windev using the database hyperfile client/serveur.
I have a table named Operation with colums (accountNumber, date, amount, operationType ).
operationType can take two values: "payment" and "withdrawal".
I want to select the List of operations done in an account and, my List should display 5 colums:
Date, accountNumber, amount, operationType and balance.
The last column (balance) should be the difference between the sum of all operations done before the current date with type "payment" and the sum of all operation done before the current date with type "withdrawal"
I try the following sql code
SELECT accountNumber, date as dateOpe, amount, operationType, (SUM (SELECT Operation.amount
FROM Operation
WHERE Operation.date<=dateOpe AND Operation.operationType='payment')
-SUM (SELECT Operation.amount
FROM Operation
WHERE Operation.date<=dateOpe AND Operation.operationType='withdrawal')) as balance
FROM Operation
But I always have an error telling me that i do not have the right to put a select in the SUM
Please can somebody help me. pease how can i write a such sql query.
thanks in advance
Please try this:
SELECT accountNumber, date, amount, operationType,
(SELECT SUM(amount) AS balance
FROM operation WHERE operationType='payment' and date=date)
-(SELECT SUM(amount) AS balance
FROM operation WHERE operationType='withdrawal' and date=date)
as balance
FROM operation
Try something like the following, using a subquery to find the SUMs. There may be a more elegant solution, but this should work.
SELECT date, accountNumber,
operationType, deposits - withdrawals AS balance
FROM Operations o INNER JOIN (
SELECT accountNumber, SUM(amount) AS withdrawals
FROM Operaions
WHERE operationType = 'withdrawal'
GROUP BY accountNumber
) a ON o.accountNumber = a.accountNumber
INNER JOIN (
SELECT accountNumber, SUM(amount) AS deposits
FROM Operations
WHERE operationType = 'deposit'
GROUP BY accountNumber
)b ON o.accountNumber = b.accountNumber
I would use the fact that a logical expression yields 0 if false and 1 if true. Therefore, Operation.amount * <logical expression> will yield 0 if the expression is false and Operation.amount if the expression is true. As a result, the following query should be close to a solution (untested):
SELECT accountNumber, date as dateOpe, amount, operationType,
SUM (Operation.amount * (Operation.date<=dateOpe AND Operation.operationType='payment')) -
SUM (Operation.amount * (Operation.date<=dateOpe AND Operation.operationType='withdrawal')) as balance
FROM Operation
Related
I am trying to run a query to gather the total items on hand in our database. However it seems i'm getting incorrect data. I am selecting selecting just the amount field and summing it using joins from separate tables based on certain parameters, however if I display additional fields such as order number, and date all of a sudden im getting different data, even though those fields are being used as filters in the query. Is it because its not in the select statement? If it needs to be in the select statement is it possible to not display them?
Here are the two queries.
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt'
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
providing a sum of 21667457.20
and with the added columns
-- Items On Hand
select CONVERT(decimal(25, 2), SUM(tw.amount)) as 'Amt', [Requested Delivery Date], sh.No_, tw.[Status]
from [Sales Header] sh
join
(
select *
from TWAllOrders
where [Status] like 'Released'
) tw
on tw.[Order Nb] = sh.No_
join
(
select *
from OnHand
) oh
on tw.No_ = oh.[Item No_]
where sh.[Requested Delivery Date] < getdate()
group by sh.[Requested Delivery Date], sh.No_, tw.[Status]
HAVING SUM(tw.Quantity) <= SUM(oh.Qty)
order by sh.[Requested Delivery Date] ASC
Providing a sum of 12319998
I'm self taught in SQL so I may be misunderstanding something obvious, thanks for the help.
With no sample data, I am going to have to demonstrate this in principle. In the latter query you have a GROUP BY meaning the scope of the values in the HAVING will differ, and thus the filtering from said HAVING will be different.
Let's take the following sample data:
CREATE TABLE dbo.MyTable (Grp char(1),
Quantity int,
Required int);
INSERT INTO dbo.MyTable (Grp, Quantity, [Required])
VALUES('a',2,7),
('a',14,2),
('b',4, 7),
('b',3,4),
('c',17,5);
Now we'll perform an overly simplified version of your query:
SELECT SUM(Quantity)
FROM dbo.MyTable
HAVING SUM(Quantity) > SUM(Required);
This brings back the value 40; which is the SUM of all the values in Quantity. A value is returned because the total SUM of Required is 25.
Now let's add a GROUP BY like your second query:
SELECT SUM(Quantity)
FROM dbo.MyTable
GROUP BY Grp
HAVING SUM(Quantity) > SUM(Required);
Now we have 2 rows, with the values 16 and 17 giving a total value of 33. That's because the rows where Grp have a value of 'B' are filtered out, as the SUM of Quantity is lower that Required for 'B'.
The same is happening in your data; in the grouped data you have groups where the HAVING condition isn't met, so those rows aren't returned.
I have a query that filters results for products which have had orders sent after an user-input date, and calculates what the quantity becomes if the order was sent after that date.
SELECT id, ProductName,
[OnHand]+ SUM([OrderJoin.Quantity]) AS Qty After
FROM Query3
WHERE Query3.ShippedDate > [Enter End Date] And
Query3.ShippedDate) Is Not Null
GROUP BY id, ProductName, OnHand;
But if I were to remove the WHERE statement, how would I make it so the Qty After would show as OnHand for the results that become NULL?
You would use NZ() to convert the NULL value to 0. Something like this:
SELECT id, ProductName,
NZ(OnHand, 0) + NZ(SUM([OrderJoin.Quantity]), 0) AS QtyAfter
...
I have a table with Three columns:
GEOID, ParcelID, and PurchaseDate.
The PKs are GEOID and ParcelID which is formatted as such:
GEOID PARCELID PURCHASEDATE
12345 AB123 1/2/1932
12345 sfw123 2/5/2012
12345 fdf323 4/2/2015
12346 dfefej 2/31/2022 <-New GEOID
What I need is an aggregation based on GEOID.
I need to count the number of ParcelIDs from last month PER GEOID
and I need to provide a percentage of that GEOID of all total sold last month.
I need to produce three columns:
GEOID Nbr_Parcels_Sold Percent_of_total
For each GEOID, I need to know how many Parcels Sold Last month, and with that Number, find out how much percentage that entails for all Solds.
For example: if there was 20 Parcels Sold last month, and 4 of them were sold from GEOID 12345, then the output would be:
GEOID Nbr_Parcels_Sold Perc_Total
12345 4 .2 (or 20%)
I am having issues with the dual aggregation. The concern is that the table in question has over 8 million records.
if there is a SQL Warrior out here who have seen this issue before, Any wisdom would be greatly appreciated.
Thanks.
Hopefully you are using SQL Server 2005 or later version, in which case you can get advantage of windowed aggregation. In this case, windowed aggregation will allow you to get the total sale count alongside counts per GEOID and use the total in calculations. Basically, the following query returns just the counts:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Total_Parcels_Sold = SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The COUNT(*) call gives you counts per GEOID, according to the GROUP BY clause. Now, the SUM(...) OVER expression gives you the grand total count in the same row as the detail count. It is the empty OVER clause that tells the SUM function to add up the results of COUNT(*) across the entire result set. You can use that result in calculations just like the result of any other function (or any expression in general).
The above query simply returns the total value. As you actually want not the value itself but a percentage from it for each GEOID, you can just put the SUM(...) OVER call into an expression:
SELECT
GEOID,
Nbr_Parcels_Sold = COUNT(*),
Percent_of_total = COUNT(*) * 100 / SUM(COUNT(*)) OVER ()
FROM
dbo.atable
GROUP BY
GEOID
;
The above will give you integer percentages (truncated). If you want more precision or a different representation, remember to cast either the divisor or the dividend (optionally both) to a non-integer numeric type, since SQL Server always performs integral division when both operands are integers.
How about using sub-query to count the sum
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
EDIT
To update another table by the result, use UPDATE under WITH()
WITH data AS
(
SELECT *
FROM [Table]
WHERE
YEAR(PURCHASEDATE) * 100 + MONTH(PURCHASEDATE) = 201505
)
UPDATE target SET
Nbr_Parcels_Sold = source.Nbr_Parcels_Sold,
Perc_Total = source.Perc_Total
FROM
[AnotherTable] target
INNER JOIN
(
SELECT
GEOID,
COUNT(*) AS Nbr_Parcels_Sold,
CONVERT(decimal(18,8), COUNT(*)) /
(SELECT COUNT(*) FROM data) AS Perc_Total
FROM
data t
GROUP BY
GEOID
) source ON target.GEOID = source.GEOID
Try the following. It grabs the total sales into a variable then uses it in the subsequent query:
DECLARE #pMonthStartDate DATETIME
DECLARE #MonthEndDate DATETIME
DECLARE #TotalPurchaseCount INT
SET #pMonthStartDate = <EnterFirstDayOfAMonth>
SET #MonthEndDate = DATEADD(MONTH, 1, #pMonthStartDate)
SELECT
#TotalPurchaseCount = COUNT(*)
FROM
GEOIDs
WHERE
PurchaseDate BETWEEN #pMonthStartDate
AND #MonthEndDate
SELECT
GEOID,
COUNT(PARCELID) AS Nbr_Parcels_Sold,
CAST(COUNT(PARCELID) AS FLOAT) / CAST(#TotalPurchaseCount AS FLOAT) * 100.0 AS Perc_Total
FROM
GEOIDs
WHERE
ModifiedDate BETWEEN #pMonthStartDate
AND #MonthEndDate
GROUP BY
GEOID
I'm guessing your table name is GEOIDs. Change the value of #pMonthStartDate to suit yourself. If your PKs are as you say then this will be a quick query.
am try to connect 3 tables but am getting error At most one record can be returned by this subquery
My code is
SELECT InvoiceNumber,
Terms(SELECT PaymentTerms
FROM PSD_customerPaymentTerms
WHERE PSD_customerPaymentTerms.PTId = NewInvoice_1.Terms
) AS Terms,
InvoiceDate,
OurQuote,
SalesPerson(SELECT FirstName
FROM Employee
WHERE Employee.EmployeeId = NewInvoice_1.SalesPerson
) AS SalesPerson,
CustomerName(SELECT CustomerName
FROM Customer
WHERE Customer.CustomerId = NewInvoice_1.CustomerName
) AS CustomerName,
OrderNumber,
GrandTotal,
(SELECT SUM(PaymentAmount)
FROM Payment_Receipt
WHERE Payment_Receipt.InvoiceNumber=NewInvoice_1.InvoiceNumber
) AS AmountPaid,
GrandTotal-IIf(AmountPaid Is Null,0,AmountPaid) AS AmountDue,
(SELECT InvoiceStatus
FROM Payment_Receipt
WHERE Payment_Receipt.InvoiceNumber=NewInvoice_1.InvoiceNumber
) AS Status -- Error getting after adding this line.
FROM NewInvoice_1;
Payment_Receipt Table contain Id, Invoice No, Customer name, Total Paid, Balance Amount, Payment Date, Payment Amount, Payment Type,Payment Remarks, InvoiceStatus.
This is my table
How to get InvoiceStatus from this table ??
One general way to solve this problem is to force the subquery to return one row by using max() on the column:
select max(someColumn)
from someTable
where ...
In case your data has multiple rows for the where clause.
While this approach will get your query working, it may not give the results you want. More likely the where clause needs work. That said, it can be very useful when diagnosing the problem, especially if you aren't sure which subquery is causing the problem you can remove the change one subquery at a time.
I am trying to get a summary of the balance per month within my database. The table has the following fields
tran_date
type (Income or Expense)
amount
I can get as far as retrieving the sum for each type for every month but want the sum for the whole month. This is my current query:
SELECT DISTINCT strftime('%m%Y', tran_date), type, SUM(amount) FROM tran WHERE exclude = 0 GROUP BY tran_date, type
This returns
032013 Income 100
032013 Expense 200
I would like the summary on one row, in this example 032013 -100.
Just use the right group by. This uses conditional aggregation, assuming that you want "income - expense":
SELECT strftime('%m%Y', tran_date), type,
SUM(case when type = 'Income' then amount when type = 'Expense' then - amount end)
FROM tran WHERE exclude = 0
GROUP BY tran_date;
If you want just the full sum, then this is easier:
SELECT strftime('%m%Y', tran_date), type,
SUM(amount)
FROM tran WHERE exclude = 0
GROUP BY tran_date;
Your original query returned type rows because "type" was in the group by clause.
Also, distinct is (almost) never needed with group by.