Using SUM() without grouping the results - mysql

I already read (this), but couldn't figure out a way to implement it to my specific problem. I know SUM() is an aggregate function and it doesn't make sense not to use it as such, but in this specific case, I have to SUM() all of the results while maintaining every single row.
Here's the table:
--ID-- --amount--
1 23
2 11
3 8
4 7
I need to SUM() the amount, but keep every record, so the output should be like:
--ID-- --amount--
1 49
2 49
3 49
4 49
I had this query, but it only sums each row, not all results together:
SELECT
a.id,
SUM(b.amount)
FROM table1 as a
JOIN table1 as b ON a.id = b.id
GROUP BY id
Without the SUM() it would only return one single row, but I need to maintain all ID's...
Note: Yes this is a pretty basic example and I could use php to do this here,but obviously the table is bigger and has more rows and columns, but that's not the point.

SELECT a.id, b.amount
FROM table1 a
CROSS JOIN
(
SELECT SUM(amount) amount FROM table1
) b
You need to perform a cartesian join of the value of the sum of every row in the table to each id. Since there is only one result of the subselect (49), it basically just gets tacked onto each id.

With MS SQL you can use OVER()
select id, SUM(amount) OVER()
from table1;
select id, SUM(amount) OVER()
from (
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) A
--- OVER PARTITION ID
PARTITION BY which is very useful when you want to do SUM() per MONTH for example or do quarterly reports sales or yearly...
(Note needs distinct it is doing for all rows)
select distinct id, SUM(amount) OVER(PARTITION BY id) as [SUM_forPARTITION]
from (
select 1 as id, 23 as amount
union all
select 1 as id, 23 as amount
union all
select 2 as id, 11 as amount
union all
select 2 as id, 11 as amount
union all
select 3 as id, 8 as amount
union all
select 4 as id, 7 as amount
) OverPARTITIONID

Join the original table to the sum with a subquery:
SELECT * FROM table1, (SELECT SUM(amount) FROM table1 AS amount) t

This does just one sum() query, so it should perform OK:
SELECT a.id, b.amount
FROM table1 a
cross join (SELECT SUM(amount) as amount FROM table1 AS amount) b

in case someone else has the same problem and without joining we can do the following
select *
,totcalaccepted=(select sum(s.acceptedamount) from cteresult s)
, totalpay=(select sum(s.payvalue) from cteresult s)
from cteresult t
end

Using Full Join -
case when you need sum of amount field from tableB and all data from tableA on behalf of id match.
SELECT a.amount, b.* FROM tableB b
full join (
select id ,SUM(amount) as amount FROM tableA
where id = '1' group by id
) a
on a.id = b.id where a.id ='1' or b.id = '1' limit 1;

Related

MYSQL - Select Only Records Where Previous Record Column Data Differs

Hoping this is possible with just sql. I have a query that returns a data set with time_stamp and hash_index columns. Basically something to the effect of:
1 1583365548 6ff11ad5536f28d66098f6d74f97d877
2 1583365554 6ff11ad5536f28d66098f6d74f97d877
3 1583365556 6ff11ad5536f28d66098f6d74f97d877
4 1583365562 a2e99acb2540d49955ef93fb2684ac25
5 1583365571 a2e99acb2540d49955ef93fb2684ac25
6 1583365572 a2e99acb2540d49955ef93fb2684ac25
7 1583365574 a2e99acb2540d49955ef93fb2684ac25
8 1583365578 a2e99acb2540d49955ef93fb2684ac25
9 1583365580 a2e99acb2540d49955ef93fb2684ac25
What I want to do is further filter this query to only include the record if the hash_index differs from the previous record. Is this something I can do without having to dump it into PHP and loop through it?
My current query is below:
SELECT
(#cnt:=#cnt + 1) AS row_number,
time_stamp,
MD5(GROUP_CONCAT(CONCAT(user_state_name,
option_id,
option_code,
item_id,
item_code))) AS hash_index
FROM
user_state
WHERE
user_id = 2
GROUP BY
time_stamp;
What is with a query like this:
SELECT t1.*
FROM user_state t1
LEFT JOIN user_state t2 ON t1.id-1 = t2.id
WHERE t1.hash_index <> t2.hash_index;
If you want to filter out adjacent duplicates, I would just use lag() and dispense with hashing and aggregation:
SELECT us.*
FROM (SELECT us.*,
LAG(time_stamp) OVER (PARTITION BY user_id ORDER BY time_stamp) as prev_ts,
LAG(time_stamp) OVER (PARTITION BY user_id, user_state_nae, option_id, option_code, item_id, item_code ORDER BY time_stamp) as prev_ts_values
FROM user_state us
WHERE user_id = 2
) t
WHERE prev_ts_values is null or prev_ts_values <> prev_ts;
You can select whichever rows you want.

How do I find duplicate values across multiple columns in Mysql?

I have a table like this
I want to check the all rows in Column A with column B and get the count of duplicates.
For example, I want to get the
count of 12 as 3(2 times in A+1 time in B)
count of 11 as 2(2 times in A+0 time in B)
count of 13 as 2(1 time in A+0 time in B)
How can I acheive it?
You can calculate the total occurrences from a union all. A where clause can show only the values that occur in the A column:
select nr
, count(*)
from (
select A as nr
from YourTable
union all
select B
from YourTable
) sub
where nr in -- only values that occur at least once in the A column
(
select A
from YourTable
)
group by
nr
having count(*) > 1 -- show only duplicates
You can combine all values in A and B then do the group by.
Then only select those values found in column A.
Select A, count(A) as cnt
From (
Select A
from yourTable
Union All
Select B
from yourTable) t
Where t.A in
(select distinct A from yourTable)
Group by t.A
Order by t.A;
Result:
A cnt
11 2
12 3
13 1
See demo: http://sqlfiddle.com/#!9/9fcfe9/3

Mysql Join query with count table records with same date

Hello i am having two different table with same field created_date (datetime)
now i want records which counts daywise records with joining table i have done for individual counting as below query :
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
and i am getting results for individuals something like this:
RESULT I NEED :
DATE(created_date) count(table1) count(table2)
2016-12-01 10 3
2016-12-02 1 0
2016-12-05 1 0
2016-11-29 1 0
2016-11-30 4 1
Now i just want to join these result WITH INDIVIDUAL VIEW COUNT ACCORDING TO TABLE can anyone please help me out with this profile....
First take a UNION between your two tables, then use conditional aggregation to determine the counts for each of the two tables. Note that I introduce a field called table_name to keep track of data from each of the two tables.
SELECT t.created_date,
SUM(CASE WHEN t.table_name = 'one' THEN 1 ELSE 0 END) AS count_table_one,
SUM(CASE WHEN t.table_name = 'two' THEN 1 ELSE 0 END) AS count_table_two
FROM
(
SELECT DATE(created_date) AS created_date, 'one' AS table_name
FROM table1
UNION ALL
SELECT DATE(created_date), 'two'
FROM table2
) t
GROUP BY t.created_date
I used DATE consistently everywhere to make the query correct.
Try This:
SELECT created_date, sum(countTable1) countTable1,
sum(countTable2) countTable2
FROM (
SELECT DATE(created_date) created_date, COUNT(*) countTable1, NULL countTable2
FROM table1 GROUP BY DAY(created_date)
UNION ALL
SELECT DATE(created_date) created_date, NULL, COUNT(*) countTable2
FROM table2 GROUP BY DAY(created_date)) t GROUP BY t.created_date
You have a problem in your queries, you are grouping by DAY(date) and showing 'date' so the result will be first date with day(date), yet repeating it to avoid misunderstanding :)
select IFNULL(A.cd, B.cd), A.cnt, B.cnt from
(SELECT DAY(created_date) d, DATE(created_date) cd, COUNT(*) cnt
FROM table1 GROUP BY DAY(created_date)) as A
LEFT JOIN
(SELECT DAY(created_date) d, DATE(created_date) cd , COUNT(*) cnt
FROM table2 GROUP BY DAY(created_date)) B ON B.d = A.d
Its not too hard just use union if no need to allow duplicate row else use union all for all(means allow duplicate as well).
SELECT DATE(created_date), COUNT(*) FROM table1 GROUP BY DAY(created_date)
UNION
SELECT DATE(created_date), COUNT(*) FROM table2 GROUP BY DAY(created_date)
SELECT T.create_date,ISNULL(T.count,0)AS Counttable1,ISNULL(X.count,0)AS Counttable2 FROM(SELECT DATE(created_date) AS create_date,COUNT(*) as count FROM table1 GROUP BY DAY(created_date)) AS T LEFTJOIN(SELECT DATE(created_date) AS create_date, COUNT(*) as count FROM table2 GROUP BY DAY(created_date))AS X ON T.create_date=X.create_date
You actually need a SQL UNION. JOIN natuarually eliminate counts becuase the maytch fields. I.e. if you had 2016-12-01 in both table1 andtable2 then a JOIN on created_date would give you a count of 1 instead of a count of 2.
SELECT DATE(total.created_date), COUNT(*)
FROM (
SELECT created_date FROM table1
UNION ALL
SELECT created_date FROM table2) as total
GROUP BY total.created_date
HERE you simply union the two tables since they have a matching column name. Then you get back every date from both tables. That is in the inner query. The outer query then does the counting.
Hope that makes sense.

SQL - How to use COUNT() with more than one table

I have a table that includes an COUNT() function that returns all the fields and counts them out. Now, I need to join another table and return both the number of rows that match and the rows that do no match. I am not exactly sure how I can use the GROUP BY and COUNT() function and get the results I need.
SELECT tb1.type, count(tb1.type) as total
FROM table1 tb1
GROUP BY tb1.type
That will return the totals for me:
RESULTS for TABLE1:
Type total
Egg 200
Cream 133
Milk 12
That's great. However, now I have another table...table 2 that has some records that match so doing that same query on that table will show something like:
RESULTS for TABLE2:
Type total
Egg 187
Cream 103
Milk 6
So, my results will need to look like this:
RESULTS for TABLE1:
Type total totalINTABLE2 totalNOTINTABLE2
Egg 200 187 13
Cream 133 103 30
Milk 12 6 6
Not sure if joining is best here, or a UNION, or EXISTS. What's getting me confused is the group by.
Well, you can simply JOIN both the resultset like
SELECT tb1.type,
tb1.total,
tb2.totalINTABLE2,
(tb1.total - tb2.totalINTABLE2) as totalNOTINTABLE2
FROM (
SELECT type, count(type) as total
FROM table1
GROUP BY type) tb1
JOIN (
SELECT type, count(type) as totalINTABLE2
FROM table2
GROUP BY type) tb2 ON tb1.type = tb2.type;
Use a CTE to calculate the total in each table then join them together:
;WITH
cte1 as (
SELECT tb1.type, count(tb1.type) as total
FROM table1 tb1
GROUP BY tb1.type
),
cte2 as (
SELECT tb2.type, count(tb2.type) as total
FROM table2 tb2
GROUP BY tb2.type
)
SELECT ISNULL(cte1.type, cte2.type) as type,
cte1.total as TotalInTable1,
cte2.total as TotalInTable2,
ISNULL(cte1.total, 0) - ISNULL(cte2.total, 0) as TotalNotInTable2
FROM cte1
FULL JOIN cte2 ON cte1.type = cte2.type

How to get last value in multiple rows in mysql?

How to select last value in multiple rows in MySQL ?
select name,date,value from table1;
Name Date Value
A 01-Jan-2013 3
A 02-Jan-2013 4
B 04-Jan-2013 2
B 05-Jan-2013 8
Result I need :
Name Date Value
A 01-Jan-2013 3
A 02-Jan-2013 4
Last_value 4
B 04-Jan-2013 2
B 05-Jan-2013 8
Last_value 8
How to do that in MySQL store procedure ?
Regards
There's no "last" record. You need to sort them by the column they should be ordered by, then only select the last row.
/* SELECT ... */ ORDER BY sort_column DESC LIMIT 1
This seems better suited for your Presentation Layer, but it is possible to write it using SQL. Something like this should work using UNION ALL to return that last record per group:
SELECT Name, Dt, Value
FROM (
SELECT Name, Dt, Value, Name Name2
FROM YourTable
UNION ALL
SELECT '' Name, 'Last_Value', T.Value, T.Name Name2
FROM YourTable T
JOIN (
SELECT Name, MAX(dt) MaxDt
FROM YourTable
GROUP BY Name
) T2 ON T.Name = T2.Name AND T.dt = T2.MaxDt
ORDER BY Name2, Dt, Value
) t
SQL Fiddle Demo
Resulting in:
NAME DT VALUE
A 2013-01-01 00:00:00 3
A 2013-01-02 00:00:00 4
Last_Value 4
B 2013-01-04 00:00:00 2
B 2013-01-05 00:00:00 8
Last_Value 8
EDIT: To get the Summed Group Total, you have to introduce the use of user defined variables. Here is an example:
SELECT Name, Dt, IF(Name='',summedTotal,Value) Value
FROM (
SELECT #summedTotal:=IF(#prevRow=Name,#summedTotal+Value,Value) summedTotal,
Name, Dt, Value, Name Name2,
#prevRow:=Name
FROM YourTable
JOIN (SELECT #summedTotal:=0) t
UNION ALL
SELECT summedTotal, '' Name, 'Last_Value', T.Value, T.Name Name2, pr
FROM (
SELECT #summedTotal:=IF(#prevRow=Name,#summedTotal+Value,Value) summedTotal,
Name, Dt, Value, Name Name2,
#prevRow:=Name pr
FROM YourTable
JOIN (SELECT #summedTotal:=0) t
) T
JOIN (
SELECT Name, MAX(dt) MaxDt
FROM YourTable
GROUP BY Name
) T2 ON T.Name = T2.Name AND T.dt = T2.MaxDt
ORDER BY Name2, Dt, Value
) t
And more SQL Fiddle
You can select the MAX value using inner join. But you haven't specified your primary key column.
SELECT
m.*
FROM mytable AS m
INNER JOIN (SELECT
MAX(primary_key_column)
FROM mytable
GROUP BY Name) AS l
ON l.primary_key_column = m.primary_key_column