rank users based on points - mysql

How can I rank the users below based on points .I really appreciate any help.
Thanks in Advance .
http://sqlfiddle.com/#!2/374db/11
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
sender varchar(255),
receiver varchar(255),
msg varchar(255),
date timestamp,
points varchar(255),
refno varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblB
(
id int(11) NOT NULL auto_increment ,
sno varchar(255),
name varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblC
(
id int(11) NOT NULL auto_increment ,
data varchar(255),
refno varchar(255),
extrarefno varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (sender, receiver,msg,date,points,refno ) VALUES
('1', '2', 'buzz ...','2011-08-21 14:11:09','10','001'),
('1', '2', 'test ...','2011-08-21 14:12:19','20','002'),
('4', '2', 'test ...','2011-08-21 14:13:19','30','003'),
('1', '3', 'buzz ...','2011-08-21 14:11:09','10','004'),
('1', '3', 'test ...','2011-08-21 14:12:19','20','005'),
('1', '4', 'buzz ...','2011-08-21 14:11:09','10','006'),
('1', '4', 'test ...','2011-08-21 14:12:19','20','007'),
('3', '4', 'test ...','2011-08-21 14:13:19','20','008'),
('2', '4', 'test ...','2011-08-21 14:13:19','20','009');
INSERT INTO tblB (sno, name ) VALUES
('1', 'Aa'),
('2', 'Bb'),
('3', 'Cc'),
('4', 'Dd'),
('5', 'Ee'),
('6', 'Ff'),
('7', 'Gg'),
('8', 'Hh');
INSERT INTO tblC (data,refno,extrarefno ) VALUES
('data1', '001', '101'),
('data2', '002', '102'),
('data3', '003', '103'),
('data4', '004', '101'),
('data5', '005', '102'),
('data6', '006', '103'),
('data7', '007', '101'),
('data8', '008', '101'),
('data9', '009', '101');
sql
SELECT *
FROM (SELECT tblA.receiver, MAX(tblA.id) AS id
FROM tblA
GROUP BY tblA.receiver
) subset JOIN
tblA
ON subset.receiver = tblA.receiver AND subset.id = tblA.id JOIN
tblB
on tblA.receiver = tblB.sno join
tblC
ON tblA.refno=tblC.refno ;

You can order the results of a query using ORDER BY. So, you can rank the rows in tblA as follows:
SELECT *
FROM tblA
ORDER BY points
However, I notice you are using varchar for the points column. If this is to hold a numerical value you probably want int or float.

Related

Find records where condition met x number of times in mysql/sql

I'm struggling with what is a complicated SQL query for me, although I believe that it is not particularly complicated. I'm close to the right answer, but not quite there yet.
My database represents a criminal abstract. I have three tables in my database (I've simplified my schema enormously for the purposes of this question): arrest, arrestcharges, and dispositions.
Each defendant can have multiple arrests (defendant table not included for simplification). Each arrest can have multiple charges, which are in the arrestcharges table. And each charge has a grade and is associated with a disposition (guilty, not guilty, etc...). The dispositions are categorized so that 0=some form of guilt disposition, 1=a non-guilty disposition.
I want to find individuals who have been convicted of a charge graded as "M1" on more than one case. If an individual has been convicted of more than M1, but they are in the same case, that person shouldn't be returned (unless they have another case with an M1 conviction).
A sqlfiddle link and the SQL to create and populate the table is below.
I believe that this query should work, but it doesn't:
select a.defendantid, count(a.id)
FROM `arrest` AS a LEFT JOIN `arrestcharges` AS ac
ON a.id=ac.arrestid LEFT JOIN `dispositions` AS d
ON ac.dispositionid=d.id
WHERE d.dispocategory=0 AND ac.grade="M1"
GROUP BY a.id HAVING COUNT(a.id) > 1 ORDER BY a.defendantid;
Based on the sql below, I expect that defendant IDs 1 and 5 should be returned since they are the only two defendants with an M1 conviction in more than one arrest. But the actual response I am getting is 2 and 5. 2 should not be returned b/c defendant 2 only has one arrest in the database.
Any thoughts on what I am doing wrong?
SQLFiddle
CREATE TABLE IF NOT EXISTS `arrest` (
`id` int(6) unsigned NOT NULL,
`defendantid` int(6) unsigned NOT NULL,
`docketno` varchar(21) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `arrestcharges` (
`id` int(6) unsigned NOT NULL,
`arrestid` int(6) unsigned NOT NULL,
`grade` varchar(2) NOT NULL,
`dispositionid` int(6) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `dispositions` (
`id` int(6) unsigned NOT NULL,
`disposition` varchar(30) NOT NULL,
`dispoCategory` int(1) unsigned NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `arrest` (`id`, `defendantid`, `docketno`) VALUES
('1', '1', 'MC-51-CR-0000222-1999'),
('2', '1', 'MC-51-CR-0000223-1999'),
('3', '1', 'MC-51-CR-0000224-1999'),
('4', '2', 'MC-51-CR-0002343-2000'),
('5', '3', 'MC-51-CR-0002349-2000'),
('6', '3', 'MC-51-CR-0002350-2000'),
('7', '3', 'MC-51-CR-0002351-2010'),
('8', '3', 'MC-51-CR-0002352-2013'),
('9', '4', 'MC-51-CR-1209293-2011'),
('10', '5', 'MC-51-CR-2389848-1999'),
('11', '5', 'MC-51-CR-3893923-1999'),
('12', '5', 'MC-51-CR-2393912-1999');
INSERT INTO `dispositions` (`id`, `disposition`, `dispoCategory`) VALUES
('1', 'Guilty', '0'),
('2', 'Not Guilty', '1'),
('3', 'Guilty Plea', '0'),
('4', 'Dismissed', '1');
INSERT INTO `arrestcharges` (`id`, `arrestid`, `grade`, `dispositionid`) VALUES
('1', '1', 'M1', '1'),
('2', '1', 'M', '2'),
('3', '2', 'F', '2'),
('4', '2', 'M1', '3'),
('5', '3', 'M1', '1'),
('6', '4', 'M2', '4'),
('7', '4', 'M1', '3'),
('8', '4', 'M1', '3'),
('9', '4', 'M1', '1'),
('10', '5', 'M1', '2'),
('11', '6', 'M1', '2'),
('12', '7', 'F2', '1'),
('13', '8', 'F3', '1'),
('14', '9', 'M1', '2'),
('15', '9', 'M1', '2'),
('16', '9', 'M1', '2'),
('17', '9', 'M1', '2'),
('18', '10', 'M1', '1'),
('19', '10', 'M1', '1'),
('20', '11', 'M2', '3'),
('21', '12', 'M1', '4'),
('22', '12', 'M1', '3');
Try this query:
select a.defendantid, count(distinct(ac.arrestid)) as count
FROM `arrest` AS a LEFT JOIN `arrestcharges` AS ac
ON a.id=ac.arrestid LEFT JOIN `dispositions` AS d
ON ac.dispositionid=d.id
WHERE d.dispocategory=0 AND ac.grade="M1"
GROUP BY a.defendantid HAVING count>1;
You should count the distinct number as distinct_count of rows you need and make use of having filter such as having distinct_count>1. This way you can ensure that the count are not getting repeated.
You appear to be aggregating by the wrong column. You need a.defendantid in the group by:
SELECT a.defendantid, count(*)
FROM `arrest` a JOIN
`arrestcharges` ac
ON a.id = ac.arrestid JOIN
`dispositions` d
ON ac.dispositionid = d.id
WHERE d.dispocategory = 0 AND ac.grade = 'M1'
GROUP BY a.defendantid
HAVING COUNT(DISTINCT a.id) > 1
ORDER BY a.defendantid;
Note that I also changed the outer joins to inner joins. If charges and dispositions are not available, then your filtering conditions cannot be met. Hence, the appropriate join is an inner join.

SUM() Query Giving Wrong Results

I have three tables in my database - staff, salary, shift.
Shift table is linked to the staff table by the staff_id, and salary by the salary_band_id which is also in staff table.
I'm trying to calculate staffs wage by doing (Shift.Total_Hours * Salary.Hourly_Wage)
Here is my query:
SELECT Staff.First_Name, Staff.Last_Name, Shift.Staff_ID, Shift.Total_Hours, Sa.Hourly_Wage,
SUM(Shift.Total_Hours * Sa.Hourly_Wage) Total
FROM Shift, Salary Sa, Staff
INNER JOIN Salary ON Staff.Salary_Band_ID = Salary.Salary_Band_ID
WHERE Shift.Staff_ID = Staff.Staff_ID
GROUP by Staff_ID
ORDER BY Total;
Tables:
CREATE TABLE Shift (
Staff_ID INT(5) NOT NULL,
Date DATE NOT NULL,
Time_Started TIME NOT NULL,
Time_Ended TIME NOT NULL,
Total_Hours DOUBLE(4,2) NOT NULL,
Confirmed ENUM('y','n') NOT NULL
)
INSERT INTO Shift
(Staff_ID, Date, Time_Started, Time_Ended, Total_Hours, Confirmed)
VALUES
('1', '2012-06-08', '9:00', '16:45', '7.75', 'y'),
('3', '2012-06-18', '13:10', '17:30', '4.33', 'y'),
('6', '2012-10-14', '11:15', '16:45', '5.5', 'y'),
('4', '2012-10-30', '10:00', '17:00', '7', 'n'),
('5', '2013-07-15', '9:10', '17:20', '8.1', 'y'),
('10', '2013-08-10', '9:00', '17:00', '8', 'n'),
('8', '2013-10-05', '10:15', '17:30', '7.25', 'y'),
('7', '2013-11-06', '9:20', '17:00', '7.66', 'y'),
('2', '2014-03-25', '9:00', '16:45', '7.75', 'n'),
('9', '2014-04-11', '9:00', '17:00', '8', 'n'),
('11', '2014-06-05', '9:00', '17:00', '8', 'y');
CREATE TABLE Salary (
Salary_Band_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Position VARCHAR(40) NOT NULL,
Hourly_Wage DOUBLE(4,2) NOT NULL
)
INSERT INTO Salary
(Position, Hourly_Wage)
VALUES
('Worker', '6'),
('Worker Manager', '8'),
('General Manager', '10.22'),
('Manager', '13.45'),
('Owner', '25'),
('Brewer', '7.76'),
('Shop Assistant', '6.12');
CREATE TABLE Staff (
Staff_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
Salary_Band_ID INT(5) NOT NULL,
First_Name VARCHAR(25) NOT NULL,
Last_Name VARCHAR(25) NOT NULL,
Part_Full_Time ENUM('f','p') NOT NULL,
DOB DATE NOT NULL,
Start_Date DATE NOT NULL,
End_Date DATE,
Address_ID INT(7) NOT NULL,
Contact_Number VARCHAR(12) NOT NULL,
Availability_ID INT(5) NOT NULL,
Brewery_ID INT(4),
Shop_ID INT(4)
)
INSERT INTO Staff
(Salary_Band_ID, First_Name, Last_Name, Part_Full_Time, DOB, Start_Date, Address_ID, Contact_Number, Availability_ID, Brewery_ID, Shop_ID)
VALUES
('1', 'Jenny', 'Bolick', 'p', '1966-08-15', '2005-06-06', '1', '+447700900969', '1', '1', '1'),
('2', 'Margit', 'Eves', 'f', '1968-01-13', '2005-10-06', '2', '07700900711', '1', '1', '2'),
('3', 'Ramonita', 'Layton', 'f', '1975-11-28', '2005-09-29', '3', '07700900336', '1', '1', '1'),
('4', 'Kattie', 'Speck', 'p', '1977-10-24', '2006-09-07', '6', '07700900615', '1', '1', '2'),
('5', 'Christa', 'Denk', 'p', '1968-03-25', '2008-04-11', '5', '07700900542', '2', '2', '4'),
('6', 'Francene', 'Scholl', 'p', '1991-08-05', '2009-05-06', '12', '07700900763', '2', '1', '4'),
('7', 'Patti', 'Tomaszewski', 'f', '1974-01-22', '2010-03-11', '11', '07700900125', '3', '2', '6'),
('7', 'Pandora', 'Laplant', 'p', '1982-02-14', '2011-10-03', '11', '+447700900118', '2', '3', '5'),
('1', 'Branden', 'Bermejo', 'f', '1985-08-15', '2012-04-18', '10', '07700900687', '4', '3', '6'),
('1', 'Lanell', 'Delao', 'p', '1987-12-24', '2012-04-20', '9', '07700900057', '5', '3', '2'),
('1', 'Floria', 'Vandermark', 'f', '1991-03-13', '2013-11-13', '6', '07700900396', '6', '4', '2');
The results all look OK, except the Totals are way off! Also it seems to only pick one salary_band.. £6.60/hour Can anyone see what I'm doing wrong?
I think this is what you are looking for, use explicit JOIN instead of implicit.
SELECT
st.First_Name,
st.Last_Name,
sh.Staff_ID,
sh.Total_Hours,
sa.Hourly_Wage,
SUM(sh.Total_Hours * sa.Hourly_Wage) Total
from Staff st
inner join Salary sa on sa.Salary_Band_ID = st.Salary_Band_ID
inner join Shift sh on sh.Staff_ID = st.Staff_ID
GROUP by st.Staff_ID
ORDER BY Total
desc
;
DEMO

rank users and join tables

How do I rank users based on points and join that user_sno with refno of another table?
I am not getting right ranking with the code below :
select *, (#rank := #rank + 1) as rank
from tblB uv
join tblC c on uv.sno=c.refno
join
(select #rank := 0) const
where uv.sno in (2, 4,5)
order by rank;
I really appreciate any help.Thanks in Advance.
http://sqlfiddle.com/#!2/9be59/12
CREATE TABLE if not exists tblB
(
id int(11) NOT NULL auto_increment ,
sno varchar(255),
name varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblC
(
id int(11) NOT NULL auto_increment ,
data varchar(255),
refno varchar(255),
points int(255),
PRIMARY KEY (id)
);
INSERT INTO tblB (sno, name ) VALUES
('1', 'Aa'),
('2', 'Bb'),
('3', 'Cc'),
('4', 'Dd'),
('5', 'Ee'),
('6', 'Ff'),
('7', 'Gg'),
('8', 'Hh');
INSERT INTO tblC (data,refno,points ) VALUES
('data1', '1', '101'),
('data2', '2', '102'),
('data3', '3', '103'),
('data4', '4', '101'),
('data5', '5', '102'),
('data6', '6', '103'),
('data7', '7', '101'),
('data8', '8', '101'),
('data9', '9', '101');
You ORDER BY rank, but you want to ORDER BY points, seems like a typo.

get latest entry even if 2 records have same timestamp

I am using the code below to retrieve the latest data w.r.t all users .But if the user had points added at the same time stamp then I would like to get the last entry not both like in the example below.How do I make sure that I get latest entry even if 2 records have same timestamp.
http://sqlfiddle.com/#!2/374db/1
I really appreciate any help.Thanks in Advance.
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
sender varchar(255),
receiver varchar(255),
msg varchar(255),
date timestamp,
points varchar(255),
refno varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblB
(
id int(11) NOT NULL auto_increment ,
sno varchar(255),
name varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblC
(
id int(11) NOT NULL auto_increment ,
data varchar(255),
refno varchar(255),
extrarefno varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (sender, receiver,msg,date,points,refno ) VALUES
('1', '2', 'buzz ...','2011-08-21 14:11:09','10','001'),
('1', '2', 'test ...','2011-08-21 14:12:19','20','002'),
('4', '2', 'test ...','2011-08-21 14:13:19','30','003'),
('1', '3', 'buzz ...','2011-08-21 14:11:09','10','004'),
('1', '3', 'test ...','2011-08-21 14:12:19','20','005'),
('1', '4', 'buzz ...','2011-08-21 14:11:09','10','006'),
('1', '4', 'test ...','2011-08-21 14:12:19','20','007'),
('3', '4', 'test ...','2011-08-21 14:13:19','20','008'),
('2', '4', 'test ...','2011-08-21 14:13:19','20','009');
INSERT INTO tblB (sno, name ) VALUES
('1', 'Aa'),
('2', 'Bb'),
('3', 'Cc'),
('4', 'Dd'),
('5', 'Ee'),
('6', 'Ff'),
('7', 'Gg'),
('8', 'Hh');
INSERT INTO tblC (data,refno,extrarefno ) VALUES
('data1', '001', '101'),
('data2', '002', '102'),
('data3', '003', '103'),
('data4', '004', '101'),
('data5', '005', '102'),
('data6', '006', '103'),
('data7', '007', '101'),
('data8', '008', '101'),
('data9', '009', '101');
///
query:
SELECT *
FROM (
SELECT tblB.*, MAX(tblA.date) AS date
FROM tblB
JOIN tblA ON tblB.sno = tblA.receiver
GROUP BY tblB.sno
) AS subset
JOIN tblA ON subset.sno = tblA.receiver
AND subset.date = tblA.date JOIN tblC ON tblA.refno=tblC.refno
The key idea is to use the id column instead of the date column. It is auto-incremented, so the biggest id should be more recent.
However, your query has another problem which is the join to tblB in the subquery. Arbitrary ("indeterminate") values from tblB would be returned in the outer query. Instead, just aggregate on tblA and move the join to tblB to the outer level:
SELECT *
FROM (SELECT tblA.receiver, MAX(tblA.id) AS id
FROM tblA
GROUP BY tblA.receiver
) subset JOIN
tblA
ON subset.receiver = tblA.receiver AND subset.id = tblA.id JOIN
tblB
on tblA.receiver = tblB.sno join
tblC
ON tblA.refno=tblC.refno ;
Order by the date AND the id. The id is set to auto increment, if the date is the same, you can assume the higher id was created after.
ORDER BY date, id

group users by message last sent

I have a table with messages sent from 1 user to another . I would like to know all messages sent or received from different users not the same .Ex: 1-2 is same as 2-1 but since 2 has made the last contact to user that message will be shown on top and also the name of the user to whom the message is sent or received from other than myself .ALso check if any message is sent from same user like 1-1 .I need to get the name too. I really appreciate any help.Thanks in Advance.
code
CREATE TABLE if not exists tblA
(
id int(11) NOT NULL auto_increment ,
sender varchar(255),
receiver varchar(255),
msg varchar(255),
date timestamp,
PRIMARY KEY (id)
);
CREATE TABLE if not exists tblB
(
id int(11) NOT NULL auto_increment ,
sno varchar(255),
name varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblA (sender, receiver,msg,date ) VALUES
('1', '2', 'buzz ...','2011-08-21 14:11:09'),
('1', '2', 'test ...','2011-08-21 14:12:19'),
('1', '2', 'check ...','2011-08-21 14:13:29'),
('1', '1', 'test2 ...','2011-08-21 14:14:09'),
('2', '1', 'check2 ...','2011-08-21 14:15:09'),
('2', '1', 'test3 ...','2011-08-21 14:16:09'),
('1', '2', 'buzz ...','2011-08-21 14:17:09'),
('1', '2', 'test ...','2011-08-21 14:18:19'),
('1', '2', 'check ...','2011-08-21 14:19:29'),
('1', '1', 'test2 ...','2011-08-21 14:10:09'),
('3', '1', 'check2 ...','2011-08-21 14:21:09'),
('3', '1', 'test3 ...','2011-08-21 14:22:09'),
('3', '2', 'buzz ...','2011-08-21 14:24:09'),
('3', '2', 'test ...','2011-08-21 14:25:19'),
('1', '3', 'check ...','2011-08-21 14:26:29'),
('1', '3', 'test2 ...','2011-08-21 14:27:09'),
('2', '3', 'check2 ...','2011-08-21 14:28:09'),
('2', '3', 'test3 ...','2011-08-21 14:29:09'),
('1', '2', 'check3 ...','2011-08-21 14:23:09');
INSERT INTO tblB (sno, name ) VALUES
('1', 'Aa'),
('2', 'Bb'),
('3', 'Cc');
I am looking on the lines of SMS inbox msgs where data comes/sent to different user and that name along with the last msg sent is displayed.How do I group that?
like this:
http://jesperbylund.com/wp-content/uploads//2011/11/Facebook-Messenger-459x900.png
I want the list of people Aa is talking to ordered by Date.
Bb
Cc
everything apart from Aa as he is the user.
I'm not sure to understand what you want, but try this:
SELECT t1.sender, t1.receiver, MAX(t1.date)
FROM tblA t1
INNER JOIN (SELECT * FROM tblA ) t2 ON t1.sender = t2.sender
AND t1.receiver = t2.receiver
AND t1.sender <> t2.receiver
GROUP BY t1.sender, t1.receiver
I did not understand what you need exactly, but you need to use LEFT JOIN to get the name.
It is something like this
SELECT a.msg AS message, b.name AS sender, c.name AS receiver, date FROM tblA a
LEFT JOIN tblB b ON b.sno = a.sender
LEFT JOIN tblB c ON c.sno = a.receiver
WHERE a.sender != a.receiver
ORDER BY date DESC