I have a DB table votes that looks like
| id | val | against_id | created_at |
-----------------------------------------------------
A | 1 | B | xxx
B | -1 | A | xxx
C | 1 | B | xxx
B | -1 | C | xxx
...
For each "vote" there are 2 rows.
I want to get a result that lists every id distinctly with the sum() of val, like:
| id | score |
-----------------
A | 42 |
B | 5 |
C | -15 |
D | 150 |
Is there an equivalent of foreach in mysql?
Your question isn't that clear but have you tried a simple, SUM/GROUP BY?
SELECT ID, SUM(Score) FROM MyTable GROUP BY ID
Related
I have some table like this
table request_buys
| id | invoice | user_id |
| -- | ----------------- | ------- |
| 3 | 20220405/01104298 | 1 |
table traces
| id | request_buy_id | status_id | created_at |
| -- | -------------- | --------- | ------------------- |
| 37 | 3 | 1 | 2022-03-27 14:12:25 |
| 38 | 3 | 2 | 2022-03-28 14:12:25 |
| 39 | 3 | 3 | 2022-03-29 14:12:25 |
| 40 | 3 | 4 | 2022-03-30 14:12:25 |
| 41 | 3 | 5 | 2022-03-31 14:12:25 |
| 42 | 3 | 6 | 2022-04-01 14:12:25 |
table statuses
| id | nama |
| -- | ----------------- |
| 1 | Order Placed |
| 2 | Order Paid |
| 3 | Accepted |
| 4 | Picked by Courier |
| 5 | In Transit |
| 6 | Delivered |
| 7 | Rated |
| 8 | Rejected |
| 9 | Canceled |
and then i try to design query like below
select
request_buys.invoice,
MAX(traces.id) as traces_id,
MAX(statuses.nama) as statuses_nama
from
`request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
inner join `statuses` on `traces`.`status_id` = `statuses`.`id`
where
`user_id` = 1
group by
request_buys.id
and produces output like the following
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Picked by Courier |
and the output i expect should be like in the table below
expect
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Delivered |
I understand my error is in MAX(statuses.nama) which I should change like removing MAX() in statuses.nama
But i just get error like this "SELECT list is not in GROUP BY clause and contains nonaggregated ... this is incompatible with sql_mode=only_full_group_by"
then I tried some to clear the value "ONLY_FULL_GROUP_BY" with a query like the following
SET sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''))
and the result is like this
output
| invoice | traces_id | statuses_nama |
| ----------------- | --------- | ----------------- |
| 20220405/01104298 | 42 | Order Placed |
and I'm really stuck at this
and how to make trace_id.status_id from the "GROUP BY" result based on request_buys.id still have a relationship with statuses.id
Your problem lies with your misuse of the MAX(statuses.nama) expression. Based on your expected output,you intend to get the statuses.nama which matches the MAX(traces.id), NOT the MAX(statuses.nama) value which returns the highest value in terms of alphabetic order. In this case, the initial letter 'P' > 'D' . I have tweaked your code a bit and tried it on workbench,supposing there are more than one invoice for a particular user.(e.g insert into request_buys values (4,'20230405/01104298',1); insert into traces values (43,4,7,'2022-04-01 14:12:25');) It works as intended.
select invoice, t.id as traces_id, s.nama as statuses_name from request_buys r
join traces t on r.id=t.request_buy_id
join statuses s on t.status_id=s.id
join
(select traces.request_buy_id, MAX(traces.id) as traces_id
from `request_buys`
inner join `traces` on `request_buys`.`id` = `traces`.`request_buy_id`
where
`user_id` = 1
group by
traces.request_buy_id ) join_t
on t.request_buy_id=join_t.request_buy_id and t.id=join_t.traces_id
;
If I'm understanding correctly, you're trying to retrieve the most recent status for each invoice. Using MAX(nama) won't return that result, because it just picks the maximum status name alphabetically.
Assuming you're using MySQL 8.x, use ROW_NUMBER() to sort and rank the statuses for each invoice, by the most recent date first. Then grab the latest one using where rowNum = 1
WITH cte AS (
SELECT rb.id AS request_buy_id
, rb.invoice
, t.id AS traces_id
, s.nama AS statuses_nama
, ROW_NUMBER() OVER(PARTITION BY rb.id ORDER BY t.created_at DESC) AS RowNum
FROM request_buys rb
INNER JOIN traces t ON rb.id = t.request_buy_id
INNER JOIN statuses s ON t.status_id = s.id
WHERE user_id = 1
)
SELECT *
FROM cte
WHERE RowNum = 1
;
Result:
request_buy_id
invoice
traces_id
statuses_nama
RowNum
3
20220405/01104298
42
Delivered
1
db<>fiddle here
So, let say I have this data
id | value | group
1 | 100 | A
2 | 120 | A
3 | 150 | B
4 | 170 | B
I want to sort it so it become like this
id | value | group
1 | 100 | A
3 | 150 | B
2 | 120 | A
4 | 170 | B
there will be more group than that, so if I the data ordered the group like (A,C,B,D,B,C,A), it will become (A,B,C,D,A,B,C)
You can add a counter column to the table, which will be used to sort the table:
select t.id, t.value, t.`group`
from (
select t.id, t.value, t.`group`,
(select count(*) from tablename
where `group` = t.`group` and id < t.id) counter
from tablename t
) t
order by t.counter, t.`group`
See the demo.
Results:
| id | value | group |
| --- | ----- | ----- |
| 1 | 100 | A |
| 3 | 150 | B |
| 2 | 120 | A |
| 4 | 170 | B |
You can approach this as
SELECT *
FROM `tablename`
ORDER BY
row_number() OVER (PARTITION BY `group` ORDER BY `group`), `group`
So I have this table
table: "tbl_hash"
------------------------------
| id | hash1 | hash2 | hash3 |
------------------------------
| 1 | a | b | c |
| 2 | a | b | c |
| 3 | a | g | d |
| 4 | a | g | d |
| 5 | a | g | d |
------------------------------
I only want to group them by hash1, hash2, and hash3. count them and only return the count which is higher by 2.
So I have this query to get the values I wanted:
select CONCAT(hash1, hash2, hash3) as hashes, COUNT(*) as count from `tbl_hash` group by hashes having `count` > 2 limit 5
^^ the query above works perfectly..
But what If I wanted to get the data and count for each row? Expected output:
--------------------------------------
| id | hash1 | hash2 | hash3 | count |
--------------------------------------
| 1 | a | b | c | 2 |
| 2 | a | b | c | 2 |
| 3 | a | g | d | 3 |
| 4 | a | g | d | 3 |
| 5 | a | g | d | 3 |
--------------------------------------
I'm also planning on converting those to a query builder using DB::table...
You may join your original table to a subquery which finds the counts for each group:
SELECT t1.*, t2.cnt
FROM tbl_hash t1
INNER JOIN
(
SELECT hash1, hash2, hash3, COUNT(*) AS cnt
FROM tbl_hash
GROUP BY hash1, hash2, hash3
HAVING COUNT(*) > 2
) t2
ON t1.hash1 = t2.hash1 AND
t1.hash2 = t2.hash2 AND
t1.hash3 = t2.hash3;
Note that what I wrote above would completely filter off any original records belonging to a hash1/hash2/hash3 group which did not have a count greater than 2. If you instead want all records, with the count, then remove the HAVING clause.
As a side note, in databases which support analytic functions, such as SQL Server and Oracle, we could write a much less verbose query using COUNT as an analytic function. At some point, mainstream versions of MySQL will also support this. But for now, we are stuck with doing a join.
I was having problems in creating counting rows by grouping based on a given field value.
For example: I have a Table A structure like this:
+------+------------+
| id | Person |
+------+------------+
| 1 | "Sandy" |
| 2 | "Piper" |
| 3 | "Candy" |
| 4 | "Pendy" |
+------------+------+
Also I have a Table B structure like this:
+------+------------+---------+
| id | Person | Point |
+------+------------+---------+
| 1 | "Sandy" | 10 |
| 2 | "Piper" | 20 |
| 3 | "Candy" | 30 |
| 4 | "Sandy" | 10 |
| 5 | "Piper" | 20 |
| 6 | "Zafar" | 30 |
+------------+------+---------+
And needed a result like:
+------+------------+---------+
| id | Person | Point |
+------+------------+---------+
| 1 | "Piper" | 40 |
| 2 | "Candy" | 30 |
| 3 | "Zafar" | 30 |
| 4 | "Sandy" | 20 |
| 5 | "Pendy" | 0 |
+------------+------+---------+
I hope the table examples are itself self-explanatory.
SELECT person
, SUM(point) total
FROM
( SELECT person,point FROM table_b
UNION
ALL
SELECT person,0 FROM table_a
) x
GROUP
BY person
ORDER
BY total DESC;
It is a simple left join with a group by
select tableA.person, sum(tableB.points) from tableA left join tableB on tableA.person = tableB.person group by tableA.person
union
select tableB.person, sum(tableB.points) from tableB left join tableA on tableA.person = tableB.person where tableA.id is null group by tableA.person
I think below sql useful to you.
select a.id, a.Person,b.total_point from (
select id, Person from tablea) as a join
(select Person, sum(Point) as total_point from tableb group by person) as b on a.person =b.person
Thank you
For example, I have the next table (IN MySQL)
| a | 1002 |
| b | 1002 |
| c | 1015 |
| a | 1005 |
| b | 1016 |
| a | 1106 |
| d | 1006 |
| a | 1026 |
| f | 1106 |
I want to select the objects that are duplicates.
| a | 1002 |
| a | 1106 |
| a | 1026 |
| a | 1005 |
| b | 1002 |
| b | 1016 |
Thank you
If I understand the question, you want to select rows where the number column is duplicated. One way to do it is to join against a subquery returns a list of number values that occur more than once.
SELECT letter, number
FROM myTable A
INNER JOIN (
SELECT number
FROM myTable
GROUP BY number
HAVING COUNT(*) > 1
) B ON A.number = B.number
As an alternative, if you want the list of all values where there are duplicates, you can use group_concat:
select col1, group_concat(col2)
from t
group by col1
having count(*) > 1
This does not return the exact format you want. Instead it would return:
| a | 1002,1106,1026,1005 |
| b | 1002,1016 |
But you might find it useful.