How to display monetary value in PostgreSQL - database

My database query is below, but I still can't display a monetary value properly. Please help me.
SELECT SUM (orders.quantity * products.price) as total,
to_char((orders.quantity * products.price), '$99,999,999.99') AS money
FROM
orders
inner join products on products.id = orders.products_id
inner join customers on customers.id = orders.customers_id
WHERE order_date BETWEEN CURRENT_DATE - INTERVAL '30 days'
AND CURRENT_DATE + INTERVAL '1 days';
My problem is that I get this error:
ERROR: column "orders.quantity" must appear in the GROUP BY clause or be used in an aggregate function

You didn't really say what your problem was, but if you use the FM format modifier as in
SELECT to_char(12345.67, '$99,999,999.99FM');
to_char
------------
$12,345.67
(1 row)
the result might be more to your liking.
To make the query work without an error, add a GROUP BY clause at the end like
... GROUP BY money

Related

SQL Server: Apply different multipliers by date

I have a table that records sales and I want a report on how much tax was paid on each item. The basic rule is all sales before April 1st had a .52% tax, all sales after that date will have a 0.5% tax.
I'm trying to get this using the following query
select ItemCode,
sum(Quantity) QuantitySold,
WhsCode as Store,
case when (docdate < '20170401') then sum(Quantity * .0052) else sum(Quantity * .005) end as Tax
from SalesTable
group by whscode,
itemcode
However I get a
DocDate' is invalid in the select list because it is not contained in
either an aggregate function or the GROUP BY clause.
error if I run it as is. Adding DocDate to the group by clause creates a mess of duplicates (On one example I went from 185 rows to 1508 rows).
Does SQL simply not allow you to use WHEN statements whose conditional is not included in the Group clause or should I be using something else?
Error is because you are using docdate directly without adding it to the group by clause.
I think this is what you want:
select ItemCode,
sum(Quantity) QuantitySold,
WhsCode as Store,
sum(price * case when docdate < '20170401' then 0.0052 else 0.005 end) as Tax
from SalesTable
group by whscode,
itemcode

How can I aggregate data based on sub query results

I have a sql query like this:
SELECT (SUM(DURATIONSECS) / 3600.00) AS LaborHrs,
(SELECT LABORLEV2 t2 FROM LABOR WHERE LABORID = t1.LABORID) As Dept
FROM Table1 t1
WHERE DTM BETWEEN 'datetime1' AND 'datetime2' AND
(SELECT LABORLEV1 FROM LABOR WHERE LABORID = t1.LABORID) = '100'
AND PAYCODEID='1'
Group BY LABORID
This gives me the correct data like this:
LaborHrs Dept
90.5000000 office
1033.2500000 retail
522.2500000 retail
217.5000000 misc
1145.5000000 misc
40.0000000 retail
However I need the results to be aggregated if the dept name is the same for instance I need the sum of all labor hours of "retail" and "misc" to be in the same column. I have tried grouping by Dept, but it did not recognize that column name.
I rewrote your query based on what I understand of your question, but I'm pretty suspicious of this part:
DTM BETWEEN 'datetime1' AND 'datetime2'
I assume that it is a datetime variable or number that you would substitute in.
If that is the case, I guess here might be the answer.
SELECT (SUM(DURATIONSECS) / 3600.00) AS LaborHrs,
, l1.LABORLEV2 AS Dept
FROM Table1 t1
JOIN LABOR l1 ON l1 ON l1.LABORID=t1.LABORID
WHERE DTM BETWEEN 'datetime1' AND 'datetime2' AND l1.LABORLEV1='100'
AND t1.PAYCODEID='1'
Group BY t1.LABORID, l1.LABORLEV2
If you want to Group some column, the column can't be a subselect, so you will have to rewrite the query using JOINS.
By what I understant of your query, you can join the tables Tabl1 and LABOR and move your conditions to a single WHERE statement, something like this:
SELECT
l.LABORLEV2 AS Dept,
(SUM(t1.DURATIONSECS) / 3600.00) AS LaborHrs
FROM Table1 t
INNER JOIN LABOR l ON t.LABORID=l.LABORID
WHERE
l.LABORLEV1='100' AND
t1.PAYCODEID='1' AND
t1.DTM BETWEEN 'datetime1' AND 'datetime2'
GROUP BY l.LABORLEV2

Using Max with Date Values with or without the Nulls

Now, after so many hours trying to figure this out, i really now need help.
I have a table which contains millions of records of about 50,000 customers. Each customer has at least 2000 transactions.
I want to have a table that holds the latest date each customer had either bought or sold something on the website.
I have tried
'FOR PURCHASES
Update tblmycustomers
set LastBoughtdate = (Select ISNULL(Max(trndate), '01-Jan-1900') from tbltransactions where Type = 'PURCHASES')
from tbltransactions.AccountRef = tblmycustomers.AccountNo
It works fine for records that have "PURCHASES" but for those who dont have PURCHASES, it saves another date which is wrong
I want it to return the default date ("01-Jan-1900") for every customer who doesn't have purchases and return the Maximum transaction date for those who has.
Please help me.
Try this:
UPDATE c
SET LastBoughtdate = ISNULL(Q.MaxBoughtDate, '1900-01-01')
FROM tblmycustomers c
LEFT JOIN
(SELECT AccountRef, MAX(trndate) AS MaxBoughtDate
FROM tblTransactions
WHERE Type = 'PURCHASES'
GROUP BY AccountRef) Q ON Q.AccountRef = AccountNo
I believe this would work. The driver table being "customers", you want to left join to the transactions...so you get all customer records even if there is no transactions. So...do something like this :)
Select cust.AccountNo
, isnull(max(trans.trndate), convert(date,'01/01/1900')) as LastBoughtDate
from tblmycustomers as cust
left join tbltransactions as trans on cust.AccountNo = trans.AccountRef
where type = 'PURCHASES'
group by cust.AccountNo
This updates based on a max transdate of an left outer joined subquery of the account number.
UPDATE
T
SET
T.LastBoughtdate=COALESCE(A.LastPurchaseDate,'01/01/1900')
FROM
tblmycustomers T
LEFT OUTER JOIN
(
SELECT
T2.AccountRef
LastPurchaseDate=MAX(trndate)
FROM
tbltransactions T2
WHERE
T2.Type='PURCHASES'
GROUP BY
T2.AccountRef
)AS A ON A.AccountRef=T.AccountNo
If your "LastBoughtdate" is DateTime. I think you need to convert the "01-01-1900'. Convert(Date, '01-01-1900', 101).

Get maximum price from a group by in SQL server

Im sorry if my title isnt very descriptive as i didnt know how to explain what i needed in sql code in a title.
Basically i have 2 tables, theres a submissions table which contains invoicenumber and totalexvat. (totalexvat is the sum of all the part_exvats in the livedata` table.
The livedata table contains invoicenumber, part_code and part_price
What i need to do is return all the data from the submissions table but also include ONLY the most expensive product in livedata which is the part_code and part_price joining the two tables together on invoicenumber
submissions
invoicenumber totalexvat
1 £123.00
2 £354.00
3 £453.00
livedata
invoicenumber part_code part_price
1 prt12345 £100.00
1 prt13643 £20.00
1 prt63456 £3.00
2 prt64232 £300.00
2 prt28258 £54.00
3 prt64232 £300.00
3 prt67252 £153.00
I hope i have explained it well enough and hope somebody can help me.
What I usually do is add a join condition and check that the price equals the max price for that item, using a subquery.
Something like this:
select *
from submissions s
inner join livedata l
on s.invoicenumber = l.invoicenumber
and l.part_price =
(select MAX(part_price)
from livedata
where invoicenumber = l.invoicenumber)
So, you could use a subquery to accomplish this, but there are a couple of potential problems. The subquery would look something like this:
SELECT submissions.totalexvat
,livedata.part_code
,livedata.part_price
FROM submissions
INNER JOIN
(SELECT invoicenumber
,MAX(part_price)
FROM livedata
GROUP BY invoicenumber) ld_max
ON submissions.invoicenumber = ld_max.invoicenumber
INNER JOIN livedata
ON ld_max.invoicenumber = livedata.invoicenumber
AND ld_max.part_price = livedata.part_price
In this example the "ld_max" subquery is identifying what the price for the most expensive part per invoice number. Then you go back to the livedata table and rejoin to get what the part_code is that corresponds to the price.
The potential problem with this is if you have multiple parts that have the same price, and that price is the maximum, then you are going to get both of those parts returned by the final join. If this is not the desired behaviour, (which it might be, it's not clear by the question), then you could avoid this by having a nested subquery and pulling only the top 1 result. But then you're just kind of arbitrarily taking one of the parts and excluding the other, which seems like not a great idea. It's also not a great idea because nested subqueries are by their very nature slow, so I'd watch out for those.
You should use windowing functions - ie : row_number()
select *
from
(
select submissions.totalexvat,
livedata.part_code,
livedata.part_price,
row_number() over (partition by submissions.invoicenumber order by part_price desc) rn
from
submissions
inner join livedata on submissions.invoicenumber = livedata.invoicenumber
) r
where rn = 1

SQL Server Stored Procedure Combining 2 table results

I have two tables:
CustomerTransaction
Id (int auto int)
CustomerName (varchar)
CustomerNumber (int)
Date (date)
WeeklyAmount (int)
Customers:
CustomerName (varchar)
CustomerNumber (int)
CustomerType (int)
CustomerDate (date)
This database is not normalized, and I can not change it. The CustomerName and what I need to do:
I need a result that will show one table with all of the information from Customers for each row that matches customer number. In CustomerTransaction, I am merely grouping all of the total sums per CustomerName of their amount.
I am using:
Select
CustomerNumber, SUM (WeeklyAmount) as Total
from
Customers.RECORDS
GROUP BY
CustomerNumber;
To get the sum of each CustomerNumber. The problem is that I can not include CustomerName in the group by. Sometimes the name of customers change over time. I was told to grab the data from Customers and it to the result above and match the CustomerNumbers
The problem is that I do not know that with a stored procedure. Anyone know how this is done?
I need all the rows matched.
Select
CustomerNumber, SUM (WeeklyAmount) as Total from
Customers.RECORDS GROUP BY CustomerNumber;
What is Customers.RECORDS? That's a bit confusing. Apart from that, I'd answer
SELECT
c.*,
sq.Total
FROM
(
SELECT
CustomerNumber,
SUM(WeeklyAmount) AS Total
FROM
CustomersTransaction
GROUP BY CustomerNumber
) sq
INNER JOIN Customers c ON c.CustomerNumber = sq.CustomerNumber
If that's not what you're looking for, you have to rephrase your question. It's a bit hard to understand where the actual problem is. Usually I'd write the query a bit different, but this should deal with the non-normalization issue.
Select
Trans.CustomerNumber, C.CustomerName, Trans.SUM (WeeklyAmount) as Total
from
CustomerTransaction Trans
join
Customers C
on
Trans.CustomerNumber=C.CustomerNumber
GROUP BY
Trans.CustomerNumber,C.CustomerName

Resources