Calculate proper total in query? - mysql

I have a table like this
| customer_id | item_id | price | amount |
I want to retrieve the amount of money each customer has spent in a single query.
I have tried:
SELECT SUM(price * amount) AS total FROM table GROUP BY customer_id
but this spits out astronomically high values for total. It cannot be correct.
I also tried
SELECT #total := #total + (price * amount) AS total FROM table
CROSS JOIN (SELECT #total := 0) CONST
GROUP BY customer_id
but this doesn't start from 0 for each customer, so the previous totals will stack up...
How do I properly retrieve the data I want?

Your initial query is correct:
SELECT SUM(price * amount) AS total
FROM table
GROUP BY customer_id;
(although I would include customer_id in the SELECT clause.)
If you have "astronomically high values" then the issue is your data. Quite possibly, the issue is that "price" is really "total" on each row.

You have to add customer id to your select clause.

I think your query should be correct. I tried on my server the following:
create table test (customer_id int, item_id int, price money, amount int)
insert test values (1,1,10,2)
insert test values (1,2,12,4)
insert test values (2,1,10,2)
insert test values (2,3,5,1)
insert test values (2,4,0.5,21)
SELECT customer_id,sum(price*amount) FROM test
GROUP BY customer_id

I think you need something like this:
select customer_id,sum(price * amount) from table group by customer_id

Related

MySQL Rollup format

How do I format the "total" row of a rollup?
Backgroup
I have a MySQL select statement that is using group by with rollup it works however, for formatting reasons I need to identify what row is a "detail" and what row is a "total." Doing this by a simple RowType column that is a 1 or a zero. I figured this would work:
select
if (MyId is null, 1,0) as RowType,
MyId,
sum(Quantity) as Quantity
from MyTable
group by MyId with rollup
This does not work. However, If I create a view of that select statement then select that view and do this it does:
Create view MyView as
select
MyId,
Sum(Quantity) as Quantity
from MyTable
group by MyId with rollup;
select
if (MyId is null, 1,0) as RowType,
MyId,
Quantity
from MyView;
Is there a better way? I am going to have to do this for a fair amount of queries and maintaining two sets is good way to have errors.
edit: screwed up my second select code and fixed it
You can put the grouped query into a subquery.
This is needed because grouping doesn't happen after selecting, so the SELECT list can't refer to the value created by WITH ROLLUP in the same query.
select
if(MyId is null, 1,0) as RowType, MyId, Quantity
FROM (
SELECT MyId, sum(Quantity) as Quantity
from MyTable
group by MyId with rollup
) AS x

How to count occurrences with derived tables in SQL?

I have this very simple table:
CREATE TABLE MyTable
(
Id INT(6) PRIMARY KEY,
Name VARCHAR(200) /* NOT UNIQUE */
);
If I want the Name(s) that is(are) the most frequent and the corresponding count(s), I can neither do this
SELECT Name, total
FROM table2
WHERE total = (SELECT MAX(total) FROM (SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) table2);
nor this
SELECT Name, total
FROM (SELECT Name, COUNT(*) AS total FROM MyTable GROUP BY Name) table1
WHERE total = (SELECT MAX(total) FROM table1);
Also, (let's say the maximum count is 4) in the second proposition, if I replace the third line by
WHERE total = 4;
it works.
Why is that so?
Thanks a lot
You can try the following:
WITH stats as
(
SELECT Name
,COUNT(id) as count_ids
FROM MyTable
GROUP BY Name
)
SELECT Name
,count_ids
FROM
(
SELECT Name
,count_ids
,RANK() OVER(ORDER BY count_ids DESC) as rank_ -- this ranks all names
FROM stats
) s
WHERE rank_ = 1 -- the most popular ```
This should work in TSQL.
Your queries can't be executed because "total" is no column in your table. It's not sufficient to have it within a sub query, you also have to make sure the sub query will be executed, produces the desired result and then you can use this.
You should also consider to use a window function like proposed in Dimi's answer.
The advantage of such a function is that it can be much easier to read.
But you need to be careful since such functions often differ depending on the DB type.
If you want to go your way with a sub query, you can do something like this:
SELECT name, COUNT(name) AS total FROM myTable
GROUP BY name
HAVING COUNT(name) =
(SELECT MAX(sub.total) AS highestCount FROM
(SELECT Name, COUNT(*) AS total
FROM MyTable GROUP BY Name) sub);
I created a fiddle example which shows both queries mentioned here will produce the same and correct result:
db<>fiddle

Is there any other option to get total count from table and distinct count of a column in same query?

I have table with 4 records with similar event name and 2 different device ids and i want total no. of records with total unique device ids.
Mysql gives perfect result but redshift is giving incorrect data.
CREATE TABLE test (
event_name varchar(50) NOT NULL,
deviceid int NOT NULL
);
INSERT INTO test (event_name, deviceid) VALUES
('install', 1),
('install', 1),
('install', 2),
('install', 1);
select count(event_name), count(distinct(deviceid)) from test;
Mysql result
You should use Distinct without ( )
SELECT count(event_name), COUNT(Distinct deviceid)
FROM Test;
Or
SELECT count(event_name), (SELECT count(deviceid) FROM (SELECT DISTINCT deviceid FROM test)) DisCount
FROM test;
As far as I know, Redshift should process this query correctly:
select count(event_name), count(distinct deviceid)
from test;
That said, in my experience with RedShift, count(distinct) was quite slow, particularly over an entire table. (This may be been fixed.)
If this is still the case, then a simple workaround is:
select sum(cnt) as row_count, count(*) as distinct_count
from (select deviceid, count(*) as cnt
from test
group by deviceid
) t
This might be significantly faster.

How can I get the X data in a SELECT QUERY

For example: If I have a table where contains:
PRICES
1
5
3
8
2
8
If I'd like the the second element, how can I get it? Only that number.. Is it possible?
Try this:
declare #x int
set #x = 3
select top 1
from (select top #x from table order by 1 desc) xx
$third_element = mysql_result(mysql_query("SELECT prices FROM the_table WHERE prices = '3'"), 0);
That selects the element, but I don't know why you would want to do it like that unless you had another row to select it from like, WHERE other_row = 'something', then you would arrive at 3.
yes it is possible
here is the solution for your answer try this.
create table prices
(
price int
)
insert into prices values (1)
insert into prices values (5)
insert into prices values (3)
insert into prices values (8)
insert into prices values (2)
insert into prices values (8)
select x.* from
(
select ROW_NUMBER()over(order by price) as RowNumber,price
from prices
)x
where x.RowNumber=3

MySQL sum() on different group bys

Ok, I have a query over two tables. I need to get two sums. I do a group by so the sum() works correctly.
SELECT sum(a.x), sum(b.y) FROM a,b GROUP BY a.n where a.n=b.m
So far this works well, but the problem is i need to group them differently for the second sum (sum(b.y)), than for the first sum (sum(a.x)).
The real query is somewhat more complex but this is my main problem.
This is what i actually try to select sum(stock.amount) - if( sold.amount IS NULL , 0, sum( sold.amount ) )
How can I solve that in one query?
since you are not writing down the tables I am gonna make a wild guess and assume the tables are like :
stock : id, item_id, amount
sold : id, item_id, amount
then again I assume that you need the stock_in_total, sold_total, left_total counts
SELECT
stock_sums.item_id,
stock_sums.st_sum as stock_in_total,
COALESCE(sold_sums.so_sum,0) as sold_total,
(stock_sums.st_sum - COALESCE(sold_sums.so_sum,0)) as left_total
FROM (
SELECT stock.item_id as item_id, SUM(stock.amount) as st_sum
FROM stock
GROUP BY item_id
) as stock_sums
LEFT JOIN (
SELECT sold.item_id as item_id, SUM(sold.amount) as so_sum
FROM sold
GROUP by item_id
) as sold_sums ON stock_sums.item_id = sold_sums.item_id
I hope this would help.
Here is how I would do it. I assume that Stock is the main table, with an ID and an amount, and that Sold maps to Stock via an ID value, and has zero to many records for each Stock item.
SELECT Q1.id, Q1.Total1, Q2.Total2
, Q1.Total1 - COALESCE(Q2.Total2,0) as Outstanding
FROM (
SELECT id, SUM(amount) as Total1
FROM Stock GROUP BY id
) as Q1
LEFT OUTER JOIN (
SELECT id, SUM(Amount) as Total2
FROM Sold GROUP BY id
) as Q2
ON Q2.id = Q1.id
Note that simply formatting your SQL into a clean way forces you to break it into logical parts and will often reveal exactly what is wrong with the query.
The example above also handles correctly the cases where there is not match in the Sold table.
Cheers,
Daniel
(Code Assumptions)
DROP TABLE Stock
CREATE TABLE Stock (
id integer
, amount decimal(10,2)
)
INSERT INTO Stock (id, amount ) VALUES ( 1, 10.1);
INSERT INTO Stock (id, amount ) VALUES ( 2, 20.2);
INSERT INTO Stock (id, amount ) VALUES ( 3, 30.3);
SELECT * FROM STOCK
DROP TABLE Sold
CREATE TABLE Sold (
id integer
, amount decimal(10,2)
)
INSERT INTO Sold (id, amount ) VALUES ( 1, 1.1);
INSERT INTO Sold (id, amount ) VALUES ( 1, 2.2);
INSERT INTO Sold (id, amount ) VALUES ( 1, 3.3);
INSERT INTO Sold (id, amount ) VALUES ( 2, 2.22);
SELECT * FROM Sold
SELECT Q1.id, Q1.Total1, Q2.Total2
, Q1.Total1 - COALESCE(Q2.Total2,0) as Outstanding
FROM (
SELECT id, SUM(amount) as Total1
FROM Stock GROUP BY id
) as Q1
LEFT OUTER JOIN (
SELECT id, SUM(Amount) as Total2
FROM Sold GROUP BY id
) as Q2
ON Q2.id = Q1.id
Results:
id Total1 Total2 Outstanding
1 10.10 6.60 3.50
2 20.20 2.22 17.98
3 30.30 30.30
REVISION
It sounds like you want the total amount of stock you have as one count for each different stock. Then you want how much stock you have left for each stock based on what has been sold. Correct?
If so check this out:
select stock, sum(a.x) as sharesBeforeSale, (sum(a.x) - sum(b.y)) as sharesAfterSale
FROM db.table1 a, db.table2 b
WHERE a.UNIQUEID = b.UNIQUEID AND b.y IS NOT NULL
GROUP BY a.UNIQUEID;
Does that accomplish what you are looking to do?
stock sharesBeforeSale sharesAfterSale
duk 100 25
orc 101 101
yrc 54 41
Enjoy!
Sample tables
db.table1 (stock owned):
UNIQUEID x stock
1 100 duk
2 101 orc
3 54 yrc
db.table2 (stock sold):
UNIQUEID y
1 75
2 0
3 13