rank users and join tables - mysql

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.

Related

sql query with join and FIND IN SET

I want to get count of post subscribed by user below is my table schema , please help me with query for the same, i trie many option but could not do it
I tried and was able to get post count of user below is my query , but here i have used static user id , i want single query to list count for all users
SELECT COUNT(*)
FROM CATMAPPING INNER JOIN
POST ON CATMAPPING.pid = POST.id
where FIND_IN_SET(CATMAPPING.cid,(select selectedcatid from subscribers where id='1'));
Desire OP
Desired Output
uemail Postcount
-----------------------------
a#s.com 4
b#s.com 8
c#s.com 10
d#s.com 4
SQL fiddel link : http://sqlfiddle.com/#!9/4fff8f/2
CREATE TABLE subscribers (
`id` int(10),
`uemail` varchar(255) DEFAULT NULL,
`selectedcatid` varchar(255) DEFAULT NULL
) ;
ALTER TABLE subscribers ADD PRIMARY KEY (`id`);
ALTER TABLE subscribers MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT;
INSERT INTO subscribers (`uemail`, `selectedcatid`) VALUES ('a#s.com', '1'),
('b#s.com', '1,3'),
('c#s.com', '1,2,3'),
('d#s.com', '3');
CREATE TABLE POST (
`id` int(10),
`title` varchar(255) DEFAULT NULL
) ;
INSERT INTO POST (`id`, `title`) VALUES ('1', 'ABC'),
('2', 'DEF'),
('3', 'GHI'),
('4', 'JKL'),
('5', 'MNO'),
('6', 'PQR'),
('7', 'STU'),
('8', 'VXZ'),
('9', 'ASO'),
('10', 'LMO');
CREATE TABLE CATMAPPING (
`cid` int(10),
`pid` int(10) DEFAULT NULL
) ;
INSERT INTO CATMAPPING (`pid`, `cid`) VALUES ('1', '1'),
('2', '2'),
('3', '3'),
('4', '1'),
('5', '2'),
('6', '3'),
('7', '3'),
('8', '3'),
('9', '1'),
('10', '1');
Here is the correct query I wrote in sql server may be some syntax is diffrent but it gives me correct result I creates a table valued function and then used it for the query .
declare #tempsub as table (subid int,selectcatId int )
insert into #tempsub
select id ,string
from subscribers
CROSS APPLY [dbo].[ufn_CSVToTable] (selectedcatid)
--select * from #tempsub
-- subid is the id of the subscribes table
SELECT subid , count(*) from post p inner join CATMAPPING c on c.pid = p.id
left join #tempsub t on t.selectcatId= c.cid
group by t.subid
-- below is the code for tabled valued function it return a table for comma seprated string
create FUNCTION dbo.[ufn_CSVToTable] ( #StringInput VARCHAR(8000) )
RETURNS #OutputTable TABLE ( [String] nVARCHAR(1000) )
AS
BEGIN
DECLARE #String nVARCHAR(1000)
WHILE LEN(#StringInput) > 0
BEGIN
SET #String = LEFT(#StringInput,
ISNULL(NULLIF(CHARINDEX(',', #StringInput) - 1, -1),
LEN(#StringInput)))
SET #StringInput = SUBSTRING(#StringInput,
ISNULL(NULLIF(CHARINDEX(',', #StringInput), 0),
LEN(#StringInput)) + 1, LEN(#StringInput))
INSERT INTO #OutputTable ( [String] )
VALUES ( #String )
END
RETURN
END

get tablename where the variable in a column matches

How to get the tablenames where nname is "new5" in all tables?.I have tried the query below but I dont get the solution(I dont think the query is right either).I really appreciate any help.Thanks in Advance.
http://sqlfiddle.com/#!2/aa1b8/7
CREATE TABLE if not exists tblC1
(
id int(11) NOT NULL auto_increment ,
nname varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblC1 (id, nname) VALUES
('1', 'new1'),
('2', 'new2'),
('3', 'new3'),
('4', 'new4'),
('5', 'new5');
CREATE TABLE if not exists tblC2
(
id int(11) NOT NULL auto_increment ,
nname varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblC2 (id, nname) VALUES
('1', 'new1'),
('2', 'new21'),
('3', 'new31'),
('4', 'new41'),
('5', 'new51');
CREATE TABLE if not exists tblC3
(
id int(11) NOT NULL auto_increment ,
nname varchar(255),
PRIMARY KEY (id)
);
INSERT INTO tblC3 (id, nname) VALUES
('1', 'new1'),
('2', 'new21'),
('3', 'new31'),
('4', 'new41'),
('5', 'new5');
Query:
SELECT *
FROM (SELECT * FROM tblC1
UNION SELECT * FROM tblC2
UNION SELECT * FROM tblC3 ) as t2
where nname = "new5"
Add the table name to your single selects:
SELECT * FROM (
SELECT
'tblC1' as tbl, tblC1.*
FROM tblC1
UNION SELECT 'tblC2', tblC2.* FROM tblC2
UNION SELECT 'tblC3', tblC3.* FROM tblC3
) t
where t.nname = "new5"
should do. You need either the outer select or a where clause for every single select of your unions. And you've got to specify the tablename,
Fiddle

COUNT in a subquery, then SUM

This should be relatively simple, but I haven't been able to figure it out.
I have a query that currently creates a table that looks like:
Teacher, course, # students in course
John Doe, Algebra 1, 3
John Doe, Algebra 2, 1
Jeff Doh, Geometry, 2
I want to also count the number of students being taught by each teacher, giving results like:
Teacher, course, # students in course, # students with teacher
John Doe, Algebra 1, 3, 4
John Doe, Algebra 2, 1, 4
Jeff Doh, Geometry, 2, 2
But I can't figure out how to produce the last column that sums all of the students being taught by a teacher across all courses.
Here's my current query (I'd also be interested in a better way to write this existing query)
SELECT
u.username AS 'teacher',
c.fullname AS 'course',
(SELECT COUNT(u1.username)
FROM prefix_user u1
JOIN prefix_user_enrolments ue1 on ue1.userid=u1.id
JOIN prefix_enrol e1 ON e1.id=ue1.enrolid
JOIN prefix_course c1 on c1.id = e1.courseid
JOIN prefix_context AS ctx1 ON ctx1.instanceid = c1.id
JOIN prefix_role_assignments AS ra1 ON ra1.contextid = ctx1.id
JOIN prefix_course_categories AS cc1 ON cc1.id=c1.category
WHERE ra1.roleid="5" ### "5" = student
AND ra1.userid=u1.id
AND e1.courseid=c1.id
AND c1.id=c.id) AS '# students in course'
FROM prefix_user u
JOIN prefix_user_enrolments ue on ue.userid=u.id
JOIN prefix_enrol e ON e.id=ue.enrolid
JOIN prefix_course c on c.id = e.courseid
JOIN prefix_context AS ctx ON ctx.instanceid = c.id
JOIN prefix_role_assignments AS ra ON ra.contextid = ctx.id
JOIN prefix_course_categories AS cc ON cc.id=c.category
WHERE ra.roleid="3" ### "3" = Teacher
GROUP BY c.id
ORDER BY cc.name, c.fullname
I wish I could just add a SUM(# students in course) column, but that doesn't work. And the interface I'm using won't let me use WITH ROLLUP.
My Schema:
CREATE TABLE prefix_user
(`id` varchar(2), `username` varchar(11))
;
INSERT INTO prefix_user
(`id`, `username`)
VALUES
('1', 'JohnDoe'),
('2', 'JaneDuh'),
('3', 'JeffDoh'),
('4', 'JackSprat'),
('5', 'WillieWinky'),
('6', 'DonaldDuck'),
('7', 'MickeyMouse')
;
CREATE TABLE prefix_user_enrolments
(`id` varchar(2), `enrolid` varchar (4), `userid` varchar(1), `status` varchar(1))
;
INSERT INTO prefix_user_enrolments
(`id`, `enrolid`, `userid`, `status`)
VALUES
('10', '1000', '1', '0'),
('11', '1001', '2', '0'),
('12', '2000', '3', '0'),
('13', '1002', '4', '0'),
('14', '2001', '5', '0'),
('15', '1003', '6', '0'),
('16', '2002', '7', '0'),
('17', '3000', '1', '0'),
('18', '3001', '7', '0')
;
CREATE TABLE prefix_enrol
(`id` varchar(4), `status` varchar (1), `courseid` varchar(3), `roleid` varchar(1))
;
INSERT INTO prefix_enrol
(`id`, `status`, `courseid`, `roleid`)
VALUES
('1000', '0', '100', '5'),
('1001', '0', '100', '5'),
('2000', '0', '200', '5'),
('1002', '0', '100', '5'),
('2001', '0', '200', '5'),
('1003', '0', '100', '3'),
('2002', '0', '200', '3'),
('3000', '0', '300', '3'),
('3001', '0', '300', '5')
;
CREATE TABLE prefix_course
(`id` varchar(3), `fullname` varchar(8), `category` varchar(2))
;
INSERT INTO prefix_course
(`id`, `fullname`, `category`)
VALUES
('100', 'Algebra1', '10'),
('200', 'Geometry', '10'),
('300', 'Algebra2', '10')
;
CREATE TABLE prefix_context
(`id` varchar(5), `instanceid` varchar(8))
;
INSERT INTO prefix_context
(`id`, `instanceid`)
VALUES
('10000', '100'),
('10001', '100'),
('20000', '200'),
('10002', '100'),
('20001', '200'),
('10003', '100'),
('20002', '200'),
('30000', '300'),
('30001', '300')
;
CREATE TABLE prefix_role_assignments
(`id` varchar(6), `roleid` varchar(1), `contextid` varchar(5), `userid` varchar(1))
;
INSERT INTO prefix_role_assignments
(`id`, `roleid`, `contextid`, `userid`)
VALUES
('100000', '5', '10000', '1'),
('100001', '5', '10001', '2'),
('200000', '5', '20000', '3'),
('100002', '5', '10002', '4'),
('200001', '5', '20001', '5'),
('100003', '3', '10003', '6'),
('200002', '3', '20002', '7'),
('300000', '3', '30000', '1'),
('300001', '5', '30001', '7')
;
CREATE TABLE prefix_role
(`id` varchar(1), `shortname` varchar(7))
;
INSERT INTO prefix_role
(`id`, `shortname`)
VALUES
('5', 'student'),
('3', 'teacher')
;
CREATE TABLE prefix_course_categories
(`id` varchar(2), `name` varchar(4))
;
INSERT INTO prefix_course_categories
(`id`, `name`)
VALUES
('10', 'math')
;
It looks like your original query may be in error. I believe JohnDoe is enrolled in Algebra 1 as a student not a teacher. I also noticed that the role is held on two tables: prefix_enrol and prefix_role_assignments - not sure if I am misinterpreting something or this is redundant data.
In my attempt below I used sub-queries to count the enrollments by courseID where the role of the enrolled is a student and count the students per teacher. There may be a more efficient way to do this, but this is what I cam up with on my first attempt:
SELECT
t.username AS 'teacher'
,c.fullname AS 'course'
,studentCountCourse.numStudents AS '# students in course'
,studentCountTeach.numStudents AS '# students with teacher'
FROM prefix_enrol AS e
INNER JOIN prefix_course AS c ON c.id = e.courseid
INNER JOIN prefix_user_enrolments AS ue ON ue.enrolid = e.id
INNER JOIN prefix_user AS t ON t.id = ue.userID AND e.roleid = 3
INNER JOIN (
SELECT
e1.courseid
,count(e1.courseid) AS numStudents
FROM prefix_enrol AS e1
WHERE e1.roleid = 5
GROUP BY e1.courseid) AS studentCountCourse ON studentCountCourse.courseid = c.id
INNER JOIN (
SELECT
t1.id
,count(t1.id) AS numStudents
FROM prefix_user AS t1
INNER JOIN prefix_user_enrolments AS ue ON ue.userid = t1.id
INNER JOIN prefix_enrol AS e ON e.id = ue.enrolid
INNER JOIN prefix_enrol AS e2 ON e2.courseid = e.courseid AND e2.roleid = 5
INNER JOIN prefix_course AS c ON c.id = e.courseid
WHERE e.roleid = 3
GROUP BY t1.id) AS studentCountTeach ON studentCountTeach.id = t.id
ORDER BY e.courseid;
If I am misunderstanding your schema please let me know by explaining what each of the tables is used for.

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

rank users based on points

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.