MySQL Query - Group By issues - mysql

The following MySQL query produces me a list of session_ids and associated usage. What i would like to do is group each session into one row with the greatest upload and download displaying. There can be multiple repeats of a user name, it has to be grouped on the session.
When I try and use group by, the greatest is not always selected.
SELECT USERNAME, ACCTSESSIONID,
IFNULL(ACCTINPUTGW ,0) * POW(2,32) + IFNULL(ACCTINPUTOCT , 0) as TOTAL_UPLOAD,
IFNULL(ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(ACCTOUTPUTOCT, 0) as TOTAL_DOWNLOAD
FROM ACCOUNTING
WHERE DATE_FORMAT(FROM_UNIXTIME(TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
ORDER BY USERNAME ASC, ACCTSESSIONID
-
USERNAME ACCTSESSIONID TOTAL_UPLOAD TOTAL_DOWNLOAD
kor1 SESSION232442 341594114 5671726599
kor1 SESSION232442 331306202 5571382940
kor1 SESSION232444 338083784 5609510490
kor1 SESSION454355 323367019 5451121083
kor2 SESSION943209 323132957 5450522047
ran32 SESSION934082 323132957 5450522047
ran62 SESSIONA34324 9532356 5450523537

You should use MIN()/MAX() aggregate functions for this:
SELECT USERNAME, ACCTSESSIONID,
MAX(IFNULL(ACCTINPUTGW ,0) * POW(2,32) + IFNULL(ACCTINPUTOCT , 0)) as TOTAL_UPLOAD,
MAX(IFNULL(ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(ACCTOUTPUTOCT, 0)) as TOTAL_DOWNLOAD
FROM ACCOUNTING
WHERE
DATE_FORMAT(FROM_UNIXTIME(TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY
USERNAME, ACCTSESSIONID
ORDER BY
USERNAME ASC, ACCTSESSIONID
More about aggregate function in MySQL: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

SELECT USERNAME, ACCTSESSIONID,
MAX(IFNULL(ACCTINPUTGW ,0) * POW(2,32) + IFNULL(ACCTINPUTOCT , 0))
AS TOTAL_UPLOAD,
MAX(IFNULL(ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(ACCTOUTPUTOCT, 0))
AS TOTAL_DOWNLOAD
FROM ACCOUNTING
WHERE DATE_FORMAT(FROM_UNIXTIME(TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY USERNAME ASC, ACCTSESSIONID
ORDER BY USERNAME ASC, ACCTSESSIONID
Note 1: Instead of IFNULL(), you can also use COALESCE(). It may be preferable as it can have more than 2 arguments and it's also used in many other RDBMSs.
Note 2: Instead of:
DATE_FORMAT(FROM_UNIXTIME(TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
you can use:
TIME_STAMP >= '2011-07-05' AND TIME_STAMP < '2011-07-06'
No need to call 2 functions for every row in the table.

Related

mysql max and min subquery using date range

I have the following query:
SELECT
(Date + INTERVAL -(WEEKDAY(Date)) DAY) `Date`,
I would like to use a subquery here to get the oldest and newest inventory from the max and min Date:
(select sellable from clabDevelopment.fba_history_daily where Date =
max(Date))
max(Date), min(Date),
ASIN,
ItemSKU,
it.avgInv,
kt.Account, kt.Country, SUM(Sessions) `Sessions`, avg(Session_Pct)`Session_Pct`,
sum(Page_Views)`Page_Views`, avg(Page_Views_Pct)`Page_Views_Pct`, avg(Buy_Box_Pct)`Buy_Box_Pct`,
sum(Units_Ordered)`Units_Ordered`, sum(Units_Ordered_B2B) `Units_Ordered_B2B`,
avg(Unit_Session_Pct)`Unit_Session_Pct`, avg(Unit_Session_Pct_B2B)`Unit_Session_Pct_B2B`,
sum(Ordered_Product_Sales)`Ordered_Product_Sales`, sum(Total_Order_Items) `Total_Order_Items`, sum(Actual_Sales) `Actual_Sales`,
sum(Orders) `Orders`, sum(PPC_Revenue) `PPC_Revenue`, sum(PPC_Orders) `PPC_Orders`,
sum(Revenue)`Revenue`, sum(Sales_Tax_Collected) `Sales_Tax_Collected`, sum(Total_Ad_Spend) `Total_Ad_Spend`, sum(Impressions) `Impressions`,
sum(Profit_after_Fees_before_Costs) `Profit_after_Fees_before_Cost`
FROM clabDevelopment.KPI_kpireport as kt
left outer join
(SELECT Month(Date) as mnth, sku, account, country, avg(sellable)`avgInv` FROM clabDevelopment.`fba_history_daily`
where sellable >= 0
group by Month(Date), sku, account, country) as it
on kt.ItemSKU = it.SKU
and kt.Account = it.account
and kt.Country = it.country
and it.mnth = Month(kt.Date)
WHERE kt.Country = 'USA' or kt.Country = 'CAN'
GROUP BY Account, Country,(Date + INTERVAL -(WEEKDAY(Date)) DAY), ItemSKU
ORDER BY Date desc
The sub-query would be from the same table I am joining on the bottom except I group by month there. So I want to run this subquery and grab the value under sellable for the date of max(Date):
(select sellable from clabDevelopment.`fba_history_daily where Date = max(Date))
When I do it this way I get invalid use of group function.
Without known your schema and the engine/db it is difficult to understand the problem. But, here is a best guess with the following schema:
fba_history_daily
- mnth
- sku
- account
- country
- sellable
- SKU
KPI_kpireport
- Account
- Country
- ItemSKU
- Account
- Date
- Country
- ASIN
The following query would give you what you're looking for. This uses a GROUP_CONCAT in order to build the required results through aggregation. With the nested query join MySQL might be building a temporary table within memory to sort through those records which would not be optimal. You can check this using EXPLAIN and you would see Using temporary in the details.
SELECT
(Date + INTERVAL -(WEEKDAY(Date)) DAY) `Date`,
ASIN,
ItemSKU,
-- MIN
(SUBSTRING_INDEX(GROUP_CONCAT(it.sellable ORDER BY it.Date ASC),',', 1) AS minSellable),
-- MAX
(SUBSTRING_INDEX(GROUP_CONCAT(it.sellable ORDER BY it.Date DESC),',', 1) AS maxSellable),
-- AVG
AVG(it.sellable) avgInv,
kt.Account, kt.Country, SUM(Sessions) `Sessions`, avg(Session_Pct)`Session_Pct`,
sum(Page_Views)`Page_Views`, avg(Page_Views_Pct)`Page_Views_Pct`, avg(Buy_Box_Pct)`Buy_Box_Pct`,
sum(Units_Ordered)`Units_Ordered`, sum(Units_Ordered_B2B) `Units_Ordered_B2B`,
avg(Unit_Session_Pct)`Unit_Session_Pct`, avg(Unit_Session_Pct_B2B)`Unit_Session_Pct_B2B`,
sum(Ordered_Product_Sales)`Ordered_Product_Sales`, sum(Total_Order_Items) `Total_Order_Items`, sum(Actual_Sales) `Actual_Sales`,
sum(Orders) `Orders`, sum(PPC_Revenue) `PPC_Revenue`, sum(PPC_Orders) `PPC_Orders`,
sum(Revenue)`Revenue`, sum(Sales_Tax_Collected) `Sales_Tax_Collected`, sum(Total_Ad_Spend) `Total_Ad_Spend`, sum(Impressions) `Impressions`,
sum(Profit_after_Fees_before_Costs) `Profit_after_Fees_before_Cost`
FROM KPI_kpireport as kt
left outer join fba_history_daily it on
kt.ItemSKU = it.SKU
and kt.Account = it.account
and kt.Country = it.country
and Month(it.Date) = Month(kt.Date)
and it.sellable >= 0
WHERE kt.Country = 'USA' or kt.Country = 'CAN'
GROUP BY Account, Country,(Date + INTERVAL -(WEEKDAY(Date)) DAY), ItemSKU
ORDER BY Date desc

SQL Server: count transaction

I have this table in SQL Server:
I want a result like this
I am going to write SQL queries to count the transaction and consolidate every month.
Thank you in advance.
First, you need to edit the column you want to group.
SELECT
A.YYYYMM,
COUNT(*) TxnCount
FROM
(
SELECT
*,
LEFT(TXN_DATE, 6) YYYYMM
FROM
Tbl
) A
GROUP BY
A.YYYYMM
Use Group By and Substring :
SELECT
SUBSTRING(CAST(TXNDate AS VARCHAR(12)),0,9) AS TXNDate,COUNT(*) AS 'TXN Count'
FROM
#tblTest
GROUP BY SUBSTRING(CAST(TXNDate AS VARCHAR(12)),0,9)
You can use GROUP BY clause to count the transaction.
Assuming your TXN Date is of date type, you can use following query:
SELECT CONVERT(VARCHAR(6), TXN_DATE, 112) AS YYYYMM, COUNT(*) AS TXN_COUNT
FROM MyTable
GROUP BY CONVERT(VARCHAR(6), TXN_DATE, 112)
ORDER BY CONVERT(VARCHAR(6), TXN_DATE, 112)
EDIT: since your TXN_DATE is int type, you can use the following
SELECT LEFT(CONVERT(VARCHAR, TXN_DATE), 6) AS YYYYMM, COUNT(*) AS TXN_COUNT
FROM MyTable
GROUP BY LEFT(CONVERT(VARCHAR, TXN_DATE), 6)
ORDER BY LEFT(CONVERT(VARCHAR, TXN_DATE), 6)

Select a custom column in MySQL

I want to display a column which calculates two custom columns.
It look something like this
SELECT to_account as account,
SUM(amount) total_claimed,
COUNT(*) as transaction_count,
((SELECT time FROM transactions WHERE to_account = account ORDER BY time DESC LIMIT 1)
- (SELECT time FROM transactions WHERE to_account = account LIMIT 1)) / 3600 as interval_hours,
(transaction_count / interval_hours) as avg_per_hour
FROM transactions
WHERE type='CLAIM' group by to_account ORDER BY COUNT(*)
I get the message "Unknown column 'thetime' in field list"
How can I work with a custom column?
You should do that using the column itself and not the alias since it's not accessible like
SELECT COUNT(*) as amount,
`time` as thetime,
(`time` / amount) as average
FROM table WHERE..
(OR) get it done in a outer query like
SELECT *, (thetime / amount) as average
FROM (
SELECT COUNT(*) as amount,
(SELECT time FROM table ...) as thetime
FROM table WHERE...)XXX;
Per your edited post, either you use the same expression again (OR) get the custom column in a outer query like
SELECT *, (transaction_count / interval_hours) as avg_per_hour
FROM (
SELECT to_account as account,
SUM(amount) total_claimed,
COUNT(*) as transaction_count,
((SELECT time FROM transactions WHERE to_account = account ORDER BY `time` DESC LIMIT 1)
- (SELECT `time` FROM transactions WHERE to_account = account LIMIT 1)) / 3600 as interval_hours
FROM transactions
WHERE type='CLAIM'
group by to_account
ORDER BY COUNT(*)
) tbl
It can be done using user defined variable,
SET #transaction_count := 0;
SET #interval_hours := 0;
SELECT to_account AS ACCOUNT,
SUM(amount) total_claimed,
#transaction_count := COUNT(*) AS transaction_count,
#interval_hours := ((SELECT TIME FROM transactions WHERE to_account = ACCOUNT ORDER BY TIME DESC LIMIT 1)
- (SELECT TIME FROM transactions WHERE to_account = ACCOUNT LIMIT 1)) / 3600 AS interval_hours,
(#transaction_count / #interval_hours) AS avg_per_hour
FROM transactions
WHERE TYPE='CLAIM' GROUP BY to_account ORDER BY COUNT(*)

Get last data for contracts

I want to select last information about client's balance from MySQL's database. I wrote next script:
SELECT *
FROM
(SELECT
contract_balance.cid,
/*contract_balance.yy,
contract_balance.mm,*/
contract_balance.expenses,
contract_balance.revenues,
contract_balance.expenses + contract_balance.revenues AS total,
(CAST(CAST(CONCAT(contract_balance.yy,'-',contract_balance.mm,'-01')AS CHAR) AS DATE)) AS dt
FROM contract_balance
/*WHERE
CAST(CAST(CONCAT(contract_balance.yy,'-',contract_balance.mm,'-01')AS CHAR) AS DATE) < '2013-11-01'
LIMIT 100*/
) AS tmp
WHERE tmp.dt = (
SELECT MAX(b.dt)
FROM tmp AS b
WHERE tmp.cid = b.cid
)
But server return:
Table 'clientsdatabase.tmp' doesn't exist
How to change this code for get required data?
Try this one in your subquery you are trying to get the MAX of (CAST(CAST(CONCAT(contract_balance.yy,'-',contract_balance.mm,'-01')AS CHAR) AS DATE)) AS dt but in subquery your aliased table tmp doesn't exist so the simplest way you can do is to calculate the MAX of dt and use GROUP BY contract_balance.cid contractor id ,i guess it will fullfill your needs
SELECT
contract_balance.cid,
contract_balance.expenses,
contract_balance.revenues,
contract_balance.expenses + contract_balance.revenues AS total,
MAX((CAST(CAST(CONCAT(contract_balance.yy,'-',contract_balance.mm,'-01')AS CHAR) AS DATE))) AS dt
FROM contract_balance
GROUP BY contract_balance.cid
Try this:
SELECT *
FROM (SELECT cb.cid, cb.expenses, cb.revenues, cb.expenses + cb.revenues AS total,
(CAST(CAST(CONCAT(cb.yy,'-',cb.mm,'-01')AS CHAR) AS DATE)) AS dt
FROM contract_balance cb ORDER BY dt DESC
) AS A
GROUP BY A.cid

SUM a grouped field

I need to SUM the contents of a column which is already worked out using GROUP BYs.. How exactly would you go about that?
The group should be based on the user name, not the entire contents of the result set. I believe this essentially a group by on that username field, but that i believe would break how the query currently works..
Example below:
SELECT A1.USERNAME, DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP),'%Y-%m-%d') AS DTTM, A1.ACCTSESSIONID,
MAX(IFNULL(A1.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTINPUTOCT, 0)) - MAX(IFNULL(A2.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTINPUTOCT, 0)) as TOTAL_UPLOAD,
MAX(IFNULL(A1.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTOUTPUTOCT, 0)) - MAX(IFNULL(A2.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTOUTPUTOCT, 0)) as TOTAL_DOWNLOAD
FROM ACCOUNTING A1
LEFT JOIN ACCOUNTING A2
ON A1.ACCTSESSIONID = A2.ACCTSESSIONID
AND DATE_FORMAT(FROM_UNIXTIME(A2.TIME_STAMP), '%Y-%m-%d') = '2011-07-04'
WHERE DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY A1.ACCTSESSIONID,A2.ACCTSESSIONID
ORDER BY A1.USERNAME
Edit:
The columns would be: TOTAL_DOWNLOAD and TOTAL_UPLOAD
Thanks # ypercube, worked a treat
SELECT A3.USERNAME
, SUM(A3.TOTAL_UPLOAD) AS FINAL_UPLOAD
, SUM(A3.TOTAL_DOWNLOAD) AS FINAL_DOWNLOAD
FROM
( SELECT
A1.USERNAME
, DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP),'%Y-%m-%d') AS DTTM
, A1.ACCTSESSIONID
, MAX(IFNULL(A1.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTINPUTOCT, 0))
- MAX(IFNULL(A2.ACCTINPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTINPUTOCT, 0))
AS TOTAL_UPLOAD
, MAX(IFNULL(A1.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A1.ACCTOUTPUTOCT, 0))
- MAX(IFNULL(A2.ACCTOUTPUTGW,0) * POW(2,32) + IFNULL(A2.ACCTOUTPUTOCT, 0))
AS TOTAL_DOWNLOAD
FROM ACCOUNTING A1
LEFT JOIN ACCOUNTING A2
ON A1.ACCTSESSIONID = A2.ACCTSESSIONID
AND DATE_FORMAT(FROM_UNIXTIME(A2.TIME_STAMP), '%Y-%m-%d') = '2011-07-04'
WHERE DATE_FORMAT(FROM_UNIXTIME(A1.TIME_STAMP), '%Y-%m-%d') = '2011-07-05'
GROUP BY A1.ACCTSESSIONID,A2.ACCTSESSIONID
ORDER BY A1.USERNAME
) AS A3
GROUP BY A3.USERNAME