how to rank users based on column num which is count of number of times user exists in table.Also if 2 users have same count it should give the user on top rank lesser than below eg: user 1 and 2 has count 3 then user 1 is rank 1 and user 2 is rank 3 and if there is new user 3 with count 1 then user 3 is rank 3 .
How do I do that? I really appreciate any help.Thank in Advance.
http://sqlfiddle.com/#!2/a9188/2
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
user varchar(255),
category int(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (user, category ) VALUES
('1', '1'),
('1', '2'),
('1', '3'),
('1', '1'),
('2', '1'),
('2', '1'),
('2', '1'),
('2', '1'),
('3', '1'),
('2', '1');
Response like: Search for category where its '1'
user category count rank
1 1 2 1
2 1 2 2
query used:
SELECT USER,
category,
count(*) AS num
FROM tblA
WHERE category=1
GROUP BY USER,
category
ORDER BY num DESC;
For example, using subquery:
SELECT
groups.*,
#rank:=#rank+1 AS rank
FROM
(select
user,
category,
count(*) as num
from
tblA
where
category=1
group by
user,
category
order by
num desc,
user) AS groups
CROSS JOIN (SELECT #rank:=0) AS init
-check your modified demo.
Related
I cannot figure out how to calculate the running average per customer up until each month.
I tried to write it in one big query using subqueries, and also joins with no luck
Here is the query I tried with a subquery:
SELECT
date_format(z1.ServiceDate, '%y-%b') as months,
(
SELECT
AVG(cc.total) + 1 AS 'avg'
FROM
(
SELECT
z.Customer_ID,
COUNT(z.BookingId) 'total'
from
Orders z
where
YEAR(z.ServiceDate) <= YEAR(z1.months) AND
MONTH(z.ServiceDate) <= MONTH(z1.months)
GROUP BY
z.Customer_ID
) cc
)
from
Orders z1
GROUP BY
YEAR(z1.ServiceDate),
MONTH(z1.ServiceDate)
I also tried to join these two queries with no luck:
SELECT date_format(Orders.ServiceDate, '%y-%b') from Orders
GROUP BY YEAR(Orders.ServiceDate), month(Orders.ServiceDate)
Could not join it with this one:
(
SELECT AVG(cc.total) + 1 AS 'avg' FROM (
SELECT Orders.Customer_ID as 'c',
COUNT(BookingId) 'total' from Orders
where year(Orders.ServiceDate) <= '2019' and month(Orders.ServiceDate)
<= '01'
GROUP BY Orders.Customer_ID
) cc
)
where '2019' and '01' would be taken from the first query.
Here is my test schema:
CREATE TABLE IF NOT EXISTS `orders` (
`BookingId` INT(6) NOT NULL,
`ServiceDate` DATETIME NOT NULL,
`Customer_ID` varchar(1) NOT NULL,
PRIMARY KEY (`BookingId`)
) DEFAULT CHARSET=utf8;
INSERT INTO `orders` (`BookingId`, `ServiceDate`, `Customer_ID`) VALUES
('1', '2019-01-03T12:00:00', '1'),
('2', '2019-01-04T12:00:00', '2'),
('3', '2019-01-12T12:00:00', '2'),
('4', '2019-02-03T12:00:00', '1'),
('5', '2019-02-04T12:00:00', '2'),
('6', '2019-02-012T12:00:00', '3');
I was expecting something like this for all months
month AVG
19-Jan 1.5
19-Feb 2
...
...
The dots is there only to show that there is much many more months in my original dataset.
For January, there was 3 bookings and two Customer_ID's. Therefore the average for bookings up until that month was 1.5. Up until February, There has been 6 bookings, and 3 Customer_IDs. Therefore the new average is 2
Join a subquery that returns the distinct months to the table and aggregate:
SELECT d.month,
COUNT(o.bookingid) / COUNT(DISTINCT o.customer_id) avg
FROM (
SELECT DISTINCT
EXTRACT(YEAR_MONTH FROM servicedate) yearmonth,
DATE_FORMAT(servicedate, '%y-%b') month
FROM orders
) d INNER JOIN orders o
ON EXTRACT(YEAR_MONTH FROM o.servicedate) <= d.yearmonth
GROUP BY d.yearmonth, d.month
See the demo.
Results:
| month | avg |
| ------ | --- |
| 19-Jan | 1.5 |
| 19-Feb | 2 |
I have a table containing zip, name and nb. If an entry has the same number (nb) as another one I wan to concatenate their names. So far it's working:
Here is SQL Fiddle with the following table and data:
CREATE TABLE `blubb` (
`zip` varchar(51) NOT NULL DEFAULT '',
`name` varchar(51) NOT NULL DEFAULT '',
`nb` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO blubb (zip, name, nb) VALUES ('1', 'aa', 1);
INSERT INTO blubb (zip, name, nb) VALUES ('2', 'bb', 2);
INSERT INTO blubb (zip, name, nb) VALUES ('3', 'cc', 3);
INSERT INTO blubb (zip, name, nb) VALUES ('4', 'dd', 2);
SELECT
zip,
name,
GROUP_CONCAT(name ORDER BY zip SEPARATOR '|') AS names
FROM blubb
GROUP BY nb
ORDER BY name ASC
Result:
+-----------------------+
| zip | name | names |
+-----------------------+
| 1 | aa | aa |
| 2 | bb | bb|dd |
| 3 | cc | cc |
+-----------------------+
But what I need is this:
+-----------------------+
| zip | name | names |
+-----------------------+
| 1 | aa | aa |
| 2 | bb | bb|dd |
| 3 | cc | cc |
| 4 | dd | dd|bb |
+-----------------------+
So if a number (nb) exists more then one time I don't want to lose it (which happend in my result). I want to select it and concatenate the names in alphabetic order. The name of the row itself should always be at first place in names followed by the other names in alphatbetic order.
Is this possible? How do I need to change my Query? I tried change the GROUP BY but nothing came closer to what I have.
You've been bitten by MySQL's notorious nonstandard extension to GROUP BY. A standard server would reject your query.
What you need is a subquery to get the list of names for each value of nb. Like so.
SELECT nb,
GROUP_CONCAT(name ORDER BY zip SEPARATOR '|') AS names
FROM blubb
GROUP BY nb
Then you join that to your detail table. Like so. (http://sqlfiddle.com/#!9/efbef6/9/0)
SELECT a.zip, a.name, b.names
FROM blubb a
JOIN (
SELECT nb,
GROUP_CONCAT(name ORDER BY zip SEPARATOR '|') AS names
FROM blubb
GROUP BY nb
) b ON a.nb = b.nb
ORDER BY a.zip
Try something like this:
SELECT q.zip, q.name,
( SELECT GROUP_CONCAT(w.name ORDER BY w.zip SEPARATOR '|')
FROM blubb AS w
WHERE w.nb = q.nb
ORDER BY w.name <> q.name, w.name ) AS names
FROM blubb AS q
ORDER BY q.name ASC
Edit
Added ordering, that the actual value would be the first. However, if there are multiple rows with the same value, all of them would go to the beginning of the list...
I would do like this:
select b.zip, b.name, g.names
from blubb b
inner join (SELECT
nb,
GROUP_CONCAT(name ORDER BY zip SEPARATOR '|') AS names
FROM blubb
GROUP BY nb) g on b.nb = g.nb
ORDER BY name ASC
Thanks to O. Jones answer it was easy to do some string manipulation to get the desired output at the end. This query is was I was looking for, maybe it's helpful to someone else:
SQL Fiddle
SELECT
a.zip,
a.name,
REPLACE(
CONCAT( a.name, '|', b.names ),
CONCAT('|', a.name),
''
) AS names
FROM blubb a
JOIN (
SELECT
nb,
GROUP_CONCAT(name ORDER BY name ASC SEPARATOR '|') AS names
FROM blubb
GROUP BY nb
) b ON a.nb = b.nb
ORDER BY a.zip
and the table with data:
CREATE TABLE `blubb` (
`zip` varchar(51) NOT NULL DEFAULT '',
`name` varchar(51) NOT NULL DEFAULT '',
`nb` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO blubb (zip, name, nb) VALUES ('1', 'aa', 1);
INSERT INTO blubb (zip, name, nb) VALUES ('2', 'bb', 2);
INSERT INTO blubb (zip, name, nb) VALUES ('3', 'cc', 3);
INSERT INTO blubb (zip, name, nb) VALUES ('4', 'dd', 2);
INSERT INTO blubb (zip, name, nb) VALUES ('5', 'ab', 2);
INSERT INTO blubb (zip, name, nb) VALUES ('5', 'cb', 2);
INSERT INTO blubb (zip, name, nb) VALUES ('6', 'ca', 2);
here is SQL Fiddle with alphabetical order on the resulting names
I have created: http://sqlfiddle.com/#!2/7bb44/1
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
userid int(255),
category int(255),
unixtime int(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (userid,category,unixtime) VALUES
('1', '1','1438689946'),
('1', '2','1438690005'),
('1', '3','1438690007'),
('5', '1','1438690009'),
('2', '1','1438690005'),
('2', '1','1438690398'),
('1', '2','1438691020'),
('1', '3','1438691028'),
('4', '2','1438690005'),
('2', '3','1438691025'),
('2', '2','1438691020'),
('3', '3','1438691022');
and
Select * from tblA group by category order by unixtime desc;
But I am getting wrong values.The values do not contain right unixtime desc.How can I make it work ? I really appreciate any help.
Try this query . If 2 unixtime are same this should display only 1
Select a.*
from tblA a join
(select category, max(unixtime) as maxut
from tblA
group by category
) c
on a.category = c.category and a.unixtime = c.maxut
group by unixtime order by a.unixtime desc;
You cannot express what you want in the way you have done it. The order by is processed after the group by. Presumably you want:
Select a.*
from tblA a join
(select category, max(unixtime) as maxut
from tblA
group by category
) c
on a.category = c.category and a.unixtime = c.maxut
order by a.unixtime desc;
how do I get count of each user contribution/appearing for that particular category.The table below has user,category .I am looking for count of hoe many times all users have contributed/appeared in the table below and rank them.
http://sqlfiddle.com/#!2/d4458/2
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
user varchar(255),
category int(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (user, category ) VALUES
('1', '1'),
('1', '2'),
('1', '3'),
('1', '1'),
('2', '1'),
('2', '1');
Response like: Search for category where its '1'
user category count rank
1 1 2 1
2 1 2 2
SELECT USER,
category,
count(*) AS num
FROM tblA
WHERE category=1
GROUP BY USER,
category
ORDER BY num DESC;
demo: http://sqlfiddle.com/#!2/d4458/10/0
SET #prev_value = NULL;
SET #rank_count = 0;
SELECT
i.*,
CASE
WHEN #prev_value = i.num THEN #rank_count
ELSE #rank_count := #rank_count + 1
END AS rank
FROM (
SELECT
user,category,COUNT(*) AS num
FROM tblA
WHERE category=1
GROUP BY user,category
ORDER BY num DESC
) i;
how to join userid to user and get the username ?
I really appreciate any help.Thanks in Advance.
http://sqlfiddle.com/#!2/ac600/1
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
user varchar(255),
category int(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblB
(
id int(11) NOT NULL auto_increment ,
username varchar(255),
userid int(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (user, category ) VALUES
('1', '1'),
('1', '2'),
('1', '3'),
('1', '1'),
('2', '1'),
('2', '1'),
('2', '1'),
('2', '1'),
('3', '1'),
('2', '1'),
('4', '1'),
('4', '1'),
('2', '1');
INSERT INTO tblB (userid, username ) VALUES
('1', 'A'),
('2', 'B'),
('3', 'C'),
('4', 'D'),
('5', 'E');
query:
SELECT
groups.*,
#rank:=#rank+1 AS rank
FROM
(select
user,
category,
count(*) as num
from
tblA
where
category=1
group by
user,
category
order by
num desc,
user) AS groups
CROSS JOIN (SELECT #rank:=0) AS init
the table looks like :
username category num Ascending rank
B 1 6 2
A 1 2 1
D 1 2 4
C 1 1 3
Use JOIN, for example:
SELECT
tblB.username,
groups.*,
#rank:=#rank+1 AS rank
FROM
(select
user,
category,
count(*) as num
from
tblA
where
category=1
group by
user,
category
order by
num desc,
user) AS groups
-- left join: in case if data integrity fails:
left join
tblB ON groups.user=tblB.userid
CROSS JOIN (SELECT #rank:=0) AS init
-check your modified demo.
You just need to do left join
SELECT
groups.*,
#rank:=#rank+1 AS rank
FROM
(select
user,
category,
count(*) as num,
tblB.username
from
tblA
left join tblB on tblA.id = tblB.userid
where
category=1
group by
user,
category
order by
num desc,
user) AS groups
CROSS JOIN (SELECT #rank:=0) AS init
See Demo
You don't need a subquery to do what you want. You can simply join in the name:
select username, category,
count(*) as num,
#rank:=#rank+1 AS rank
from tblA join
tblB
on tblA.user = tblB.userId CROSS JOIN
(SELECT #rank:=0) AS cont
where category = 1
group by username, category
order by num desc, username;
TblB has an odd format. Normally, the auto-incrementing id would be the "userid" for the table.
Also, because you are selecting only one category, strictly speaking it is unnecessary to put category in the group by statement.
EDIT:
You cannot create a view with this method of doing the rank because it uses variables. It isn't easy to generate a rank on aggregated data in a view-compatible way in MySQL.