I have a table that records product clicks. For example:
productId ipv4 date flag
100 32.59.xx.xx 2015-11-29 1
100 32.59.xx.xx 2015-11-29 1
101 32.59.xx.xx 2015-11-29 1
100 64.34.xx.xx 2015-11-29 1
100 64.34.xx.xx 2015-11-29 1
I need to group by productId but only count one productId-ipv4 pair. I need to ignore any duplicate clicks on a product from the same user.
Expected result:
productId COUNT(*) SUM(flag)
100 2 2
101 1 1
How would I structure the query?
Something like this:
select productid, count(distinct ipv4), count(distinct ipv4, flag)
from foo
group by productId
Check sqlfiddle: http://sqlfiddle.com/#!9/ac487/1
Related
I have a table structure and values as:-
used_items
id item_name qty
24 Potatoes 0
25 Potatoes 500
26 test 88
27 Wheat 3
28 abc 10
I want to group according to item_name such as query should return single item_name where qty!=0.
I have used this query-
SELECT * from used_items group by item_name having qty!='0'
This query doesn't return Potatoes, the result-
id item_name qty
26 test 88
27 Wheat 3
28 abc 10
Expected Result-
id item_name qty
25 Potatoes 500
26 test 88
27 Wheat 3
28 abc 10
It should also return the item_name Potatoes with non zero value including in the group.
How can I achieve this?
Edits-
I have used Group by because i want unique item_name and it should skip the item_name if qty is 0 for all same item_name. But the query skips if atleast one of the row qty is 0(such as Potatoes).
Also, if qty is 0, it should get the row which matches the item_name according to the id ascending. Hope i am clear, for eg;
The data:-
id item_name qty
24 Potatoes 0
25 Potatoes 500
27 Potatoes 400
28 test 88
29 Wheat 3
30 abc 10
Expected result, returning unique item_name with first inserted non-zero value
id item_name qty
25 Potatoes 500
28 test 88
29 Wheat 3
30 abc 10
The structure of your query is the problem. When you GROUP BY by you are working with aggregating data and the HAVING clause functions on an aggregate. Your query doesn't do any aggregation at the moment.
So you'd need to aggregate the qty by SUM or AVG or MAX in order to have an effective group by. I also wouldn't think about excluding the id here, because it's not useful in the aggregate.
For example:
SELECT item_name, MIN(qty)
FROM used_items
GROUP BY item_name
HAVING MIN(qty) <> '0'
You can also consider using DISTINCT if you just want to find unique combinations. Again, the id won't be useful with DISTINCT. DISTINCT does not aggregate.
For example:
SELECT DISTINCT item_name, qty
FROM used_items
WHERE qty <> '0';
Having a second look, if all you want to do is exclude all 0 qty rows, all you need is:
SELECT id, item_name, qty
WHERE qty <> '0';
Finally, just check that the data type of qty is actually a VARCHAR or CHAR like type. It really would make a lot more sense if it was an INT.
EDIT:
You can use a WHERE clause with a GROUP BY to exclude qty values that are 0. And since qty is an INT data type, you don't need to put values in quotes '.
Example:
SELECT item_name, MAX(qty)
FROM used_items
WHERE qty <> 0
GROUP BY item_name
I hope this helps.
If you want for each item_name the 1st non 0 (for the quantity) row then you can do it with a correlated subquery:
SELECT t.*
FROM tablename t
WHERE t.id = (SELECT MIN(id) FROM tablename WHERE item_name = t.item_name AND qty <> 0)
See the demo.
Results:
> id | item_name | qty
> -: | :-------- | --:
> 25 | Potatoes | 500
> 28 | test | 88
> 29 | Wheat | 3
> 30 | abc | 10
Why are you using the group by without an aggregate function? If I understood your question, to achieve your expected result you can just..
SELECT DISTINCT(item_name), qty from used_items where qty!='0
SELECT MAX(id) id, item_name, SUM(qty) qty
FROM used_items
GROUP BY item_name
HAVING SUM(qty) > 0
ORDER BY MAX(id);
should do it for you. See this. https://www.db-fiddle.com/f/9hmTPkNkhpjqGrFvUeLzjW/1
MAX(id)'s purpose is to get a valid id column value even from your GROUP BY operation.
You were misusing MySQL's notorious non-standard GROUP BY handling and therefore getting strange results.
I have the following data,
id emp_id csa_taken
1 100 2
2 100 2
3 100 0
4 100 2
5 101 2
6 101 2
7 101 0
8 101 0
I expect a result with count where csa_taken=2 for individual employee.
expected result:
emp_id count_csa_taken
100 3
101 2
I have tried the following query with a failed attempt.
Select count(employee_id) From $employeeCSA where csa_taken=2
Please suggest as I am new to sql.
If I understand you correctly you like to count all employees with a cas_taken of two. As there are multiple entries for the csa_taken for one employee you need to group them.
E.g.:
SELECT COUNT(*) FROM $employeeCSA WHERE csa_taken = 2 GROUP_BY employee_id
Please note that COUNT(*) counts the rows (not the fields).
You also need group by. Try like:
Select count(employee_id),emp_id From $employeeCSA where csa_taken=2
group by emp_id
If i understand correctly, then you can try this:
SELECT emp_id,COUNT(emp_id) from dbo.Sample WHERE csa_token = 2 GROUP BY emp_id
How to get those entries which have more than 1 records?
If it doesn't make sense... let me explain:
From the below table I want to access the sum of the commission of all rows where type is joining and "they have more than 1 entry with same downmem_id".
I have this query but it doesn't consider more entries scenario...
$search = "SELECT sum(commission) as income FROM `$database`.`$memcom` where type='joining'";
Here's the table:
id mem_id commission downmem_id type time
2 1 3250 2 joining 2019-09-22 13:24:40
3 45 500 2 egbvegr new time
4 32 20 2 vnsjkdv other time
5 23 2222 2 vfdvfvf some other time
6 43 42 3 joining time
7 32 353 5 joining time
8 54 35 5 vsdvsdd time
Here's the expected result: it should be the sum of the id no 2, 7 only
ie. 3250+353=whatever.
It shouldn't include id no 6 because it has only 1 row with the same downmem_id.
Please help me to make this query.
Another approach is two levels of aggregation:
select sum(t.commission) income
from (select sum(case when type = 'joining' then commission end) as commission
from t
group by downmem_id
having count(*) > 1
) t;
The main advantage to this approach is that this more readily supports more complex conditions on the other members of each group -- such as at most one "joining" record or both "joining" records and no more than two "vnsjkdv" records.
Use EXISTS:
select sum(t.commission) income
from tablename t
where t.type = 'joining'
and exists (
select 1 from tablename
where id <> t.id and downmem_id = t.downmem_id
)
See the demo.
Results:
| income |
| ----- |
| 3603 |
You can use subquery that will find all downmem_id having more than one occurrence in the table.
SELECT Sum(commission) AS income
FROM tablename
WHERE type = 'joining'
AND downmem_id IN (SELECT downmem_id
FROM tablename t
GROUP BY downmem_id
HAVING Count(id) > 1);
DEMO
I have an orders table with the following fields : id, name, price_paid
The easiest part is this:
SELECT
name,
SUM(price_paid) AS total_price_paid
FROM
Orders GROUP BY
name
How should I modify my SQL statement so I get the following at the output?
name, total_price_paid, purchase_level
Where purchase level would be:
1 if total_price_paid is in the range of 0 - 100
2 if in a range 101-350
and 3 if above 350
Thank you in advance.
SELECT
name,
SUM(price_paid) AS total_price_paid,
CASE WHEN SUM(price_paid) BETWEEN 0 AND 100 THEN 1
WHEN SUM(price_paid) BETWEEN 101 AND 350 THEN 2
WHEN SUM(price_paid) > 350 THEN 3 END AS purchase_level
FROM
Orders
GROUP BY
name
Use conditional sum:
SELECT
name,
SUM(IF(price_paid BETWEEN 0 AND 100, price_paid, 0)) AS sum_0_100,
SUM(IF(price_paid BETWEEN 101 AND 350, price_paid, 0)) AS sum_101_350,
SUM(IF(price_paid>350, price_paid, 0)) AS sum_350_plus
FROM
Orders
GROUP BY
name
Or else, with level:
SELECT
name,
SUM(price_paid),
CASE
WHEN price_paid BETWEEN 0 AND 100 THEN 1
WHEN price_paid BETWEEN 101 AND 350 THEN 2
WHEN price_paid>350 THEN 3
END AS level
FROM
Orders
GROUP BY
name,
-- don't forget group then:
level
Difference between those two queries are that fires will result in pivot while second will result in plain rows grouping.
I have this result set from my query:
OrderId CustomerId ProducerId CustomerPayment ProducerPayment
1 1 3 10 5
1 1 4 10 5
1 2 3 10 5
1 2 4 10 5
I need to return this result into this:
OrderId UserId Payment
1 1 20
1 2 20
1 3 10
1 4 10
Just combining the CustomerId and ProducerId into UserId. Same with the Payment Columns.
Is there any way to achieve this with using just a simple select and group by? I'm avoiding temp tables, calling multiple same queries and like for optimization. I hope this is possible.
Thanks a lot
SELECT
OrderId,
CustomerID AS UserId,
SUM (CustomerPayment) As Payment
FROM orders
UNION ALL
SELECT
OrderId,
ProducerId AS UserId,
SUM (ProducerPayment) As Payment
FROM orders
Try something like this:
select
OrderId,
CustomerId,
sum(CustomerPayment) Payment,
group_concat(OrderId separator ',') listOrders /* list all OrderID's from the user and separates these with a , */
from your_table
group by CustomerId
Dont know how you query looks like atm?