making an unique column value after order by mysql - mysql

So, my problem is that I have a list of customers (table now has around 100k records) with income per each customer. When I group it by country I get around 60 countries with sum of income. Than I need to order it by the income DESC, my query looks something like this:
SELECT s2.i,s1.year,s1.short_c,s1.country,s1.uges FROM
(SELECT u.year,k.short_c,s.country, IFNULL(ROUND(SUM(u.income)),0) as uges
FROM im_income u,im_contact k,td_countries s
WHERE u.year=2012
AND u.customer_id=k.id
AND k.kat='K'
AND k.short_c=s.short_c
GROUP BY k.short_c, u.year
ORDER BY u.year ASC,uges DESC) s1
CROSS JOIN
(SELECT #i:=#i+1 as i FROM (SELECT #i:= 0) AS i) s2
And I know that this with CROSS JOIN is wrong since it is not giving me what I need, but is there a way to make an unique id after ORDER BY since I need to order countries with income DESC and than assing them id that would represent a rank number???
Result looks like this now:
+-+----+-------+---------+------+
|i|year|short_c|country |uges |
+-+----+-------+---------+------+
|1|2012|USA |United S.|123456|
+-+----+-------+---------+------+
|1|2012|RU |Russia |23456 |
+-+----+-------+---------+------+
And I would want it in this way, but to assign after order by the unique i value:
+-+----+-------+---------+------+
|i|year|short_c|country |uges |
+-+----+-------+---------+------+
|1|2012|USA |United S.|123456|
+-+----+-------+---------+------+
|2|2012|RU |Russia |23456 |
+-+----+-------+---------+------+
|3| | | | |
+-+----+-------+---------+------+
Any help would be appreciated.

I think this is what you are looking for:
SELECT #i := #i + 1 as i, s1.year, s1.short_c, s1.country, s1.uges
FROM (SELECT u.year,
k.short_c,
s.country,
IFNULL(ROUND(SUM(u.income)),0) as uges
FROM im_income u join
im_contact k
on u.customer_id = k.id join
td_countries s
on k.short_c = s.short_c
WHERE u.year = 2012 AND k.kat = 'K'
GROUP BY k.short_c, u.year
) s1
CROSS JOIN
(SELECT #i:= 0) const
ORDER BY year, uges desc;
The variable evaluation occurs when the results are being "output", after the order by.
I also fixed your join syntax. You should learn to use the explicit join rather than implicit joins in the where clause.

Related

Group by Member but Order by Count Product

I want to display promos from all members in the order of the highest number of clicks in the last 1 week, terms that 1 member only displays 1 promo
like this:
id promo
member/sales
order by count
9
B
10
5
A
9
6
M
8
The following is the data table
Tabel Promo (product_promo)>> | ppo_id | ppo_sales | ppo_content |
Tabel click recording (ipslsprod) >> | idip | dipp (id promo) | mxd (datetime visit click)
Tabel sales (sales) >> | id | name |
And I've written down the code
SELECT pp.*,
s.*,
Count(ip.dipp) AS VIEWS
FROM product_promo pp
left join (SELECT *
FROM ipslsprod
WHERE mxd >= Date_sub(Now(), interval 7 day)) ip
ON ip.dipp = pp.ppo_id
left join sales s
ON pp.ppo_sales = s.id
GROUP BY pp.ppo_id
ORDER BY VIEWS DESC
But showing more than 1 member
id promo
member/sales
order by count
9
B
10
5
A
9
4
B
7
I've tried changing
GROUP BY pp.ppo_sales
The data is messy.
Please help and instructions,
I want to display each sales only 1 product_promo in the order of the highest number of ip.dipps.
You can use aggregation and window functions. I'm not sure exactly what the query is, but I think:
SELECT v.*
FROM (SELECT s.id, pp.id_product_promo, COUNT(*) AS views ,
ROW_NUMBER() OVER (PARTITION BY s.id ORDER BY COUNT(*) DESC) as seqnum
FROM sales s JOIN
product_promo pp
ON pp.ppo_sales = s.id JOIN
ipslsprod ip
ON ip.dipp = pp.ppo_id
WHERE ip.mxd >= DATE_SUB(NOW(),INTERVAL 7 day)) ip
GROUP BY s.id, pp.id_product_promo
) v
WHERE seqnum = 1;
Maybe this will enlighten a bit more:
SELECT your_fields, MAX(count_click) FROM [table] GROUP BY count_click ORDER BY count_click
From there you can add all the date related stuff to fine-tune the query.
Perhaps it is a good idea to read up on the MySQL INTERVAL for that.

SQL: join 2 tables based on column value and select row values where grouped column value is max

Ive got this query and I want to get all names from those clients that have the highest price of a day.
If multiple clients exist having the same max price, they shall be selected too.
I managed to get the customers with max price grouped by date but I dont think it gives me both customers if they have the same max value on the same day.
The names should be distinct.
The output needs to be as follows:
| Name (asc) |
------------------
| customer name |
| customer name |
| ...... |
The Orders table looks as follows:
|Client|Price|Orderdate |
------------------------
|1 |100.0|2010.01.10|
|... |... | ..... |
and the Client table:
|Client_NR|Name |
-----------------------
|1 |customer#001|
|2 |customer#002|
select distinct k1.NAME from Orders a LEFT JOIN Order b on a.Orderdate = b.Orderdate
JOIN Client k1 on k1.Client_NR = a.Client
where a.Price IN
(SELECT MAX(a.Price) from Order a group by Orderdate)
order by NAME asc
I presume my error lies within the Join Client line but I just cant figure it out.
Ive tried to use a.price = b.price in the first join but the test would fail.
Any advise is highly appreciated.
WITH cte AS ( SELECT Client.Name,
RANK() OVER (PARTITION BY Orders.Orderdate
ORDER BY Orders.Price DESC) rnk
FROM Client
JOIN Orders ON Client.Client_NR = Orders.Client )
SELECT Name
FROM cte
WHERE rnk = 1
ORDER BY Name

Determine ranking with single mysql query

I am selecting a set of items from my table and determine their ranking to display this on my page, my code for selecting the items:
<?
$attra_query=mysqli_query($link, "select * from table WHERE category ='4'");
if(mysqli_num_rows($attra_query)>
0){
while($attra_data=mysqli_fetch_array($attra_query,1)){
?>
In the while loop I determine the ranking for each of those items like so:
SELECT COUNT(mi.location) + 1 rank
FROM table m
LEFT JOIN (
SELECT id,location,country, ROUND(COALESCE(total_rating/total_rating_amount,0),10) rating_per_vote
FROM table WHERE category = '4'
) mi
ON mi.location = m.location
AND mi.country = m.country
AND mi.rating_per_vote > ROUND(COALESCE(m.total_rating/m.total_rating_amount,0),10)
WHERE m.id = '$attra_id';
I figure this is highly inefficient, is there a way to combine the 2 queries into a single one so I don't have to run the ranking query for each item separately ?
//EDIT
Sample data:
id | location | country | category | total_rating | total_rating_amount
1 berlin DE 4 12 2
2 munich DE 4 9 1
Vote system is 1-10 points, for the sample data berlin has received a total rating of 12 with 2 votes, munich has received a rating of 9 with 1 vote, so berlin would have a rating of 6/10 and munich a rating of 9/10 and therefore should be ranked #1
SELECT COUNT(m.id) rank, m.id
FROM
(SELECT * FROM table WHERE category = '4') m
LEFT JOIN (
SELECT id,location,country, ROUND(COALESCE(total_rating/total_rating_amount,0),10) rating_per_vote
FROM table WHERE category = '4'
) mi
ON (mi.location = m.location
AND mi.country = m.country
AND mi.rating_per_vote > ROUND(COALESCE(m.total_rating/m.total_rating_amount,0),10))
OR mi.id=m.id
GROUP BY m.id
This should do I suppose. I don't know if this is the best possible solution.
In MySQL, you can do the ranking using variables. It is a bit hard to tell what you want to rank by from your query, but it would be something like this:
select t.*, (#rn := #rn + 1) as ranking
from table t cross join
(select #rn := 0) vars
where category = '4'
order by rating_per_vote;
If you provide sample data and desired results, it would be possible to refine this solution.

Identifying groups in Group By

I am running a complicated group by statement and I get all my results in their respective groups. But I want to create a custom column with their "group id". Essentially all the items that are grouped together would share an ID.
This is what I get:
partID | Description
-------+---------+--
11000 | "Oven"
12000 | "Oven"
13000 | "Stove"
13020 | "Stove"
12012 | "Grill"
This is what I want:
partID | Description | GroupID
-------+-------------+----------
11000 | "Oven" | 1
12000 | "Oven" | 1
13000 | "Stove" | 2
13020 | "Stove" | 2
12012 | "Grill" | 3
"GroupID" does not exist as data in any of the tables, it would be a custom generated column (alias) that would be associated to that group's key,id,index, whatever it would be called.
How would I go about doing this?
I think this is the query that returns the five rows:
select partId, Description
from part p;
Here is one way (using standard SQL) to get the groups:
select partId, Description,
(select count(distinct Description)
from part p2
where p2.Description <= p.Description
) as GroupId
from part p;
This is using a correlated subquery. The subquery is finding all the description values less than the current one -- and counting the distinct values. Note that this gives a different set of values from the ones in the OP. These will be alphabetically assigned rather than assigned by first encounter in the data. If that is important, the OP should add that into the question. Based on the question, the particular ordering did not seem important.
Here's one way to get it:
SELECT p.partID,p.Description,b.groupID
FROM (
SELECT Description,#rn := #rn + 1 AS groupID
FROM (
SELECT distinct description
FROM part,(SELECT #rn:= 0) c
) a
) b
INNER JOIN part p ON p.description = b.description;
sqlfiddle demo
This gets assigns a diferent groupID to each description, and then joins the original table by that description.
Based on your comments in response to Gordon's answer, I think what you need is a derived table to generate your groupids, like so:
select
t1.description,
#cntr := #cntr + 1 as GroupID
FROM
(select distinct table1.description from table1) t1
cross join
(select #cntr:=0) t2
which will give you:
DESCRIPTION GROUPID
Oven 1
Stove 2
Grill 3
Then you can use that in your original query, joining on description:
select
t1.partid,
t1.description,
t2.GroupID
from
table1 t1
inner join
(
select
t1.description,
#cntr := #cntr + 1 as GroupID
FROM
(select distinct table1.description from table1) t1
cross join
(select #cntr:=0) t2
) t2
on t1.description = t2.description
SQL Fiddle
SELECT partID , Description, #s:=#s+1 GroupID
FROM part, (SELECT #s:= 0) AS s
GROUP BY Description

SQL query with multiple tables, possible to apply group by only to count(*)?

I am trying to list bookjobs info for jobtype 'N' and having publishers creditcode of 'C'. Then, add a count of the total number of po's (purchase orders- from table pos) for each row of the previous queries' output. Can you use group by to apply only to that count and not to the rest of the query? Do i have to use a join? My attempts thus far have been unsuccessful.
These are the tables i am working with:
bookjobs:
+--------+---------+----------+
| job_id | cust_id | jobtype |
+--------+---------+----------+
publishers:
+---------+------------+------------+
| cust_id | name | creditcode |
+---------+------------+------------+
pos:
+--------+-------+------------+-----------+
| job_id | po_id | po_date | vendor_id |
+--------+-------+------------+-----------+
This is what i came up with, although it is wrong (count is not grouped to job_id):
select b.*, (select count(*) from pos o) as count
from bookjobs b, publishers p, pos o
where b.cust_id=p.cust_id
and b.job_id=o.job_id
and b.jobtype='N'
and p.creditcode='C';
I believe i need to have the count grouped by job_id, but not the rest of the query. Is this possible or do i need to use a join? I tried a few joins but couldn't get anything to work. Any help appreciated.
Try this sql
select b.*, (select count(*) from pos where job_id=o.job_id) as count
from bookjobs b, publishers p, pos o
where b.cust_id=p.cust_id
and b.job_id=o.job_id
and b.jobtype='N'
and p.creditcode='C';
Based on what you describe, I would assume that your original query would return duplicate rows. You can fix this by pre-aggregating the pos table and then joining it in:
select b.*, o.cnt
from bookjobs b join
publishers p
on b.cust_id = p.cust_id join
(select job_id, count(*) as cnt
from pos o
group by job_id
) o
on b.job_id = o.job_id
where b.jobtype = 'N' and p.creditcode = 'C';