add total sum of one column every set of related rows - sql

I would like to receive sql output like this:
ORDER # | LINE # | PRICE
---------------------------------
AAA | 1 | 20
AAA | 2 | 30
AAA | 3 | 10
TOTAL_PRICE = 60
BBB | 1 | 50
BBB | 2 | 20
TOTAL_PRICE = 70
GRAND_TOTAL = 130
Is this possible?
Thanks for any help

Aggregating by order and adding the grand total.
select order
, sum(price) total
from table
group by order
union all
select 'grand total' order
, sum(price) total
from table
;
This provides the raw data in tabular structure. For generating a specifically formatted outpout you will need a reporting tool. some rdbms have command line clients that can assist you with this (eg. oracle's sqlplus), if you don't expect too fancy a result.
Edit (per OP's comment):
Including the original order lines and presenting the rows in the desired order requires additional machinery:
select *
from (
select order seq
, order
, line
, price total
from table
union all
select order || '-0' seq
, 'TL('||order||')' order
, null line
, total
from (
select order
, sum(price) total
from table
group by order
)
union all
select 'ZZZZZZ-9' seq
, grand total' order
, null line
, sum(price) total
from table
)
order by seq
;
The actual composition of the seq column depends on the actual format of order codes (rarely a problem, since their format is usually constrained in a well-defined way).
As said before, for fancier outputs you are probably better off using a suitable tool.

Please also Try:
SELECT Order, line, SUM(price) total_price
FROM table_name
GROUP BY order, line, price WITH ROLLUP;
hope this helps.

Related

SQL - how to get as a query result both a column and the sum of that column's values

I have a complicated stored procedure that calculates a column with numeric values and returns it as a part of data-set containing other columns as well. I am trying to find a way to return in the same query the SUM of that special column as well. I use SQL Management Studio and was thinking to use an OUT parameter or even a RETURN value. But if there is a more SQL-ish way to do it will definitely prefer it.
SELECT
OrID, QN, PRID, PCKID, Person, Price, CSID,
CASE
WHEN (COUNT(*) OVER (PARTITION BY OrID)) > 1
THEN Price * 0.2
ELSE Price * 0.1
END AS Commission
FROM
( < my subquery > )
I would also like to add SUM(Commission) to the the results of the above statement.
If my data is (partial)
OrID|Price
----+-----
1 | 100
2 | 100
2 | 50
3 | 80
I will get the following result
OrID|Price|Commission
----+-----+----------
1 | 100 | 10
2 | 100 | 20
2 | 50 | 10
3 | 80 | 8
And somewhere I would also like to see the SUM of the last column - 48
Something like Excel's SUM function at the end of the Commission column
You can use a subquery:
SELECT s.*, SUM(Commission) OVER (PARTITION BY OrId) as sum_commission
FROM (SELECT OrID, QN, PRID, PCKID, Person, Price, CSID
(CASE WHEN (count(*) OVER (PARTITION BY OrID)) > 1
THEN Price*0.2
ELSE Price*0.1
END) AS Commission
FROM (< my subquery >
) s
) s;
I assume you want it by OrId. If not remove the partition by.
Try using the with Rollup command. It does what you want
https://technet.microsoft.com/en-us/library/ms189305%28v=sql.90%29.aspx?f=255&MSPPError=-2147217396

One one customer from table

I need help using Teradata SQL and I hope you can help.
I have a table that looks like this:
email | article number | discount | price
customer01#test.de | 123 | 15 | 999
customer01#test.de | 456 | 30 | 1999
customer01#test.de | 789 | 30 | 999
From this table I want only row from the customer which has the highest discount and (if there are multiple rows with the same discount) the lowest price.
So in the example above, I only want the 3rd line. How can I write a SQL query for this?
The most flexible way utilizes ROW_NUMBER:
select * from myTable
QUALIFY
ROW_NUMBER()
OVER (PARTITION BY email -- for each customer, otherwise remove it
ORDER BY discount DESC, price ASC) = 1
The simplest way to do this is via a simple select statement ordered by discount (descending) and then by price (ascending).
SELECT * FROM customers
ORDER BY discount DESC, price ASC
LIMIT 1
Use NOT EXISTS to return a row only if there are no other row with a higher discount, or another row with same discount and a lower price.
select *
from tablename t1
where not exists (select 1 from tablename t2
where t2.discount > t1.discount
or (t2.discount = t1.discount and t2.price < t1.price))

Query to Calculate totalcost based on description

I have question regarding sql script. I have a custom view, below is the data
================================================================================
ql_siteid | ql_rfqnum | ql_vendor | ql_itemnum | totalcost_option | description
================================================================================
SGCT | 1002 | VND001 | ITEM002 | 12500 |
SGCT | 1002 | VND001 | ITEM001 | 1350 |
SGCT | 1002 | VND002 | ITEM002 | 11700 |
SGCT | 1002 | VND002 | ITEM001 | 1470 | Nikon
SGCT | 1002 | VND002 | ITEM001 | 1370 | Asus
================================================================================
And i want the result like below table:
VND001 = 13850
VND002 = Asus 13070, Nikon 13170
where 13850 is come from 12500+1350, 13070 is come from 11700+1370 and 13170 is come from 11700+1470. All the cost is calculated from totalcost_option and will be group based on vendor
So please give me some advise
To get the exact output you required use the following statement: (where test_table is your table name):
SELECT ql_vendor || ' = ' ||
LISTAGG( LTRIM(description||' ')||totalcost, ', ')
WITHIN GROUP (ORDER BY description)
FROM (
WITH base_cost AS (
SELECT ql_vendor, SUM(totalcost_option) sumcost
FROM test_table WHERE description IS NULL
GROUP BY ql_vendor
),
individual_cost AS (
SELECT ql_vendor, totalcost_option icost, description
FROM test_table WHERE description IS NOT NULL
)
SELECT ql_vendor, sumcost + NVL(icost,0) totalcost, description
FROM base_cost LEFT OUTER JOIN individual_cost USING (ql_vendor)
)
GROUP BY ql_vendor;
Details:
The Outer select just takes the individual rows and combines them to the String-representation. Just remove it and you will get a single row for each vendor/description combination.
The inner select joins two sub-select. The first one gets the base_cost for each vendor by summing up all rows without a description. The second gets the individual cost for each row with a description.
The join combines them - and left outer joins displays the base_cost for vendors which don't have a matching row with description.
Assuming you have a version of Oracle 11g or later, using ListAgg will do the combination of the comma separated tuples for you. The rest of the string is generated by simply concatenating the components together from an intermediate table - I've used a derived table (X) here, but you could also use a CTE.
Edit
As pointed out in the comments, there's a whole bunch more logic missing around the Null description items I missed in my original answer.
The following rather messy query does project the required result, but I believe this may be indicative that a table design rethink is necessary. The FULL OUTER JOIN should ensure that rows are returned even if there are no base / descriptionless cost items for the vendor.
WITH NullDescriptions AS
(
SELECT "ql_vendor", SUM("totalcost_option") AS "totalcost_option"
FROM MyTable
WHERE "description" IS NULL
GROUP BY "ql_vendor"
),
NonNulls AS
(
SELECT COALESCE(nd."ql_vendor", mt."ql_vendor") AS "ql_vendor",
NVL(mt."description", '') || ' '
|| CAST(NVL(mt."totalcost_option", 0)
+ nd."totalcost_option" AS VARCHAR2(30)) AS Combined
FROM NullDescriptions nd
FULL OUTER JOIN MyTable mt
ON mt."ql_vendor" = nd."ql_vendor"
AND mt."description" IS NOT NULL
)
SELECT x."ql_vendor" || ' = ' || ListAgg(x.Combined, ', ')
WITHIN GROUP (ORDER BY x.Combined)
FROM NonNulls x
WHERE x.Combined <> ' '
GROUP BY x."ql_vendor";
Updated SqlFiddle here
Your logic seems to be: If description is always NULL for a vendor then you want that as the total cost. Otherwise, you want the NULL value of description added to all the other values. The following query implements this logic. The output is in a different format from your answer -- this format is more consistent with a SQL result set:
select ql_vendor,
(sum(totalcost_option) +
(case when description is not null then max(totalcost_null) else 0 end)
)
from (select v.*, max(description) over (partition by ql_vendor) as maxdescription,
sum(case when description is null then totalcost_option else 0 end) over (partition by ql_vendor) as totalcost_null
from view v
) t
where maxdescription is null or description is not null
group by ql_vendor, description;

Access Union/Pivot to Swap Columns and Rows

Access 2010 here. I have a query (Thank you Andomar!):
SELECT Inspection.Date, count(*) AS [# Insp], sum(iif(Disposition = 'PASS',1,0)) AS [# Passed], sum(iif(Disposition = 'FAIL',1,0)) AS [# Failed], sum(iif(Disposition = 'PASS',1,0)) / count(*) AS [% Acceptance]
FROM Inspection
WHERE Disposition in ('PASS', 'FAIL') AND ((Inspection.Date) Between Date() And Date()-30)
GROUP BY Date;
That gives a table like this:
Date | # Insp | # Passed | # Failed | % Acceptance
11/26/2012 | 7 | 5 | 2 | 71
11/27/2012 | 8 | 4 | 4 | 50
...
I am looking to use this query to make a "table" for a sub-form that will be below a graph, for reference only. The formatting of the "table" is of importance, as it needs both Column (Date) and Row headings. I have table in parentheis to emphasize that the table is generated in real time; in other words, not stored as an Access object.
The end result will be someting like this:
Date | 11/26/2012 | 11/27/2012 ...
# Insp | 7 | 8
# Passed | 5 | 4
# Failed | 2 | 4
% Acceptance | 71 | 50
It seems to be an optimal case, as the axis are just flipped, but for the life of me, I cannot find a solution that does not destroy the data. A Crosstab Query only gave me filtering on one or more categories against a single value. Is this something a union would be used for; or a pivot? Would a transform be needed? It seems like it should be such a simple problem. Is this something that can be done in SQL or would VBA be needed to arrange the "table?" Thanks for the help!
These links do seem applicable:
Columns to Rows in MS Access
how to pivot rows to columns
This will have to be a two-step process to transform. First you will have to rotate the data in your current query to be in rows instead of columns, then you will have to transform the dates into columns instead of rows.
The query will be something like this:
TRANSFORM max(val) as MaxValue
SELECT col
FROM
(
SELECT [Date], '# Insp' as Col, [# Insp] as val
FROM yourQuery
UNION ALL
SELECT [Date], '# Passed' as Col, [# Passed] as val
FROM yourQuery
UNION ALL
SELECT [Date], '# Failed' as Col, [# Failed] as val
FROM yourQuery
UNION ALL
SELECT [Date], '% Acceptance' as Col, [% Acceptance] as val
FROM yourQuery
)
GROUP BY col
PIVOT [Date]
I am guessing the your current query is saved in your database, you will replace the yourQuery in my example with the name of your query.
I just tested this in MS Access 2003 with the values in your sample above and it produced the result you want.

SQL to find the date when the price last changed

Input:
Date Price
12/27 5
12/21 5
12/20 4
12/19 4
12/15 5
Required Output:
The earliest date when the price was set in comparison to the current price.
For e.g., price has been 5 since 12/21.
The answer cannot be 12/15 as we are interested in finding the earliest date where the price was the same as the current price without changing in value(on 12/20, the price has been changed to 4)
This should be about right. You didn't provide table structures or names, so...
DECLARE #CurrentPrice MONEY
SELECT TOP 1 #CurrentPrice=Price FROM Table ORDER BY Date DESC
SELECT MIN(Date) FROM Table WHERE Price=#CurrentPrice AND Date>(
SELECT MAX(Date) FROM Table WHERE Price<>#CurrentPrice
)
In one query:
SELECT MIN(Date)
FROM Table
WHERE Date >
( SELECT MAX(Date)
FROM Table
WHERE Price <>
( SELECT TOP 1 Price
FROM Table
ORDER BY Date DESC
)
)
This question kind of makes no sense so im not 100% sure what you are after.
create four columns, old_price, new_price, old_date, new_date.
! if old_price === new_price, simply print the old_date.
What database server are you using? If it was Oracle, I would use their windowing function. Anyway, here is a quick version that works in mysql:
Here is the sample data:
+------------+------------+---------------+
| date | product_id | price_on_date |
+------------+------------+---------------+
| 2011-01-01 | 1 | 5 |
| 2011-01-03 | 1 | 4 |
| 2011-01-05 | 1 | 6 |
+------------+------------+---------------+
Here is the query (it only works if you have 1 product - will have to add a "and product_id = ..." condition on the where clause if otherwise).
SELECT p.date as last_price_change_date
FROM test.prices p
left join test.prices p2 on p.product_id = p2.product_id and p.date < p2.date
where p.price_on_date - p2.price_on_date <> 0
order by p.date desc
limit 1
In this case, it will return "2011-01-03".
Not a perfect solution, but I believe it works. Have not tested on a larger dataset, though.
Make sure to create indexes on date and product_id, as it will otherwise bring your database server to its knees and beg for mercy.
Bernardo.