SELECT DISTINCT users.id as expert_id, users.firstname, users.lastname
, projects.id as project_id, projects.project_title
, projects.project_budget, projects.created as project_created
FROM USERS
RIGHT JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN projects ON projects.id = project_skills.project_id
WHERE projects.status = 1
此查询为我提供了与用户相关的不同项目,但我想限制每位专家的项目数。例如,我想要与专家相关的项目,但项目数量最多可达10个。我的查询需要一个限制工具。我怎么能这样做?谢谢
答案 0 :(得分:1)
您可以将此技术应用于您的问题:OLAP functions
只需将选择限制为等级< = 10
答案 1 :(得分:0)
如果MySQL有row_number,这将非常容易,但事实并非如此。
因此,您需要将Andomar的answer修改为类似的问题。
set @num := 0, @projectid:= -1;
SELECT DISTINCT users.id as expert_id, users.firstname, users.lastname, projects.id as project_id, projects.project_title, projects.project_budget, projects.created as project_created
FROM
USERS
RIGHT JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN projects ON projects.id = project_skills.project_id
JOIN
(select
users.id uid,
project.id pid,
@num := if(@projectid= projects.id, @num + 1, 1)
as row_number,
@projectid:= project.id
from USERS
RIGHT JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN projects ON projects.id = project_skills.project_id
WHERE projects.status = 1
order by
users.id, project.id desc
) as projectNum
on users.id = pid
and projects.id = pid
where projectNum.row_number <= 10
在data.stackoverflow.com中查看此查询,了解如何在支持窗口的数据库中执行此操作
答案 2 :(得分:0)
使用rownum进行subselect限制应该可以正常工作
SELECT DISTINCT users.id as expert_id, users.firstname, users.lastname, projects.id as project_id, projects.project_title, projects.project_budget, projects.created as project_created
FROM USERS
RIGHT JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN (select * from (select a.project_id, additional_rows from projects) a where rownum < 11) projects_skills ON projects.id = project_skills.project_id
WHERE projects.status = 1
答案 3 :(得分:0)
可以使用stored procedures
,in-memory tables
和使用WHILE
循环的控制流的组合来实现:
DELIMITER $$
DROP PROCEDURE IF EXISTS `Get10ProjectsPerUserByStatus`$$
-- 1. DEFINE STORED PROCEDURE
CREATE PROCEDURE `Get10ProjectsPerUserByStatus`(_status INT)
BEGIN
-- 2. DECLARE VARIABLES AND IN-MEMORY TABLES
DECLARE _id INT;
DROP TABLE IF EXISTS temp_user;
DROP TABLE IF EXISTS temp_project_user;
CREATE TABLE temp_user (id INT) ENGINE=MEMORY;
CREATE TABLE temp_project_user (p_id INT, u_id INT) ENGINE=MEMORY;
-- 3. ADD ALL USERS AND LOOP BY REMOVING 1 USER AT A TIME
INSERT INTO temp_user SELECT id FROM users;
WHILE (SELECT COUNT(*) FROM temp_user) > 0 DO
SET _id = (SELECT MIN(id) FROM temp_user);
INSERT INTO temp_project_user
SELECT ps.project_id, _id
FROM project_skills ps
JOIN expert_skills es ON ps.skill_id = es.skill_id
WHERE es.expert_id = _id
LIMIT 10;
DELETE FROM temp_user WHERE id = _id;
END WHILE;
-- 4. SELECT FROM IN-MEMORY TABLE AND JOIN TO EXISTING SCHEMA
SELECT DISTINCT t.u_id AS expert_id,
u.firstname,
u.lastname,
t.p_id AS project_id,
p.project_title,
p.project_budget,
p.created AS project_created
FROM temp_project_user t
INNER JOIN users u ON u.id = t.u_id
INNER JOIN projects p ON p.id = t.p_id;
-- 5. DROP IN-MEMORY TABLES
DROP TABLE temp_user;
DROP TABLE temp_project_user;
END$$
DELIMITER ;
-- 6. CALL STORED PROCEDURE & DROP WHEN FINISHED
CALL Get10ProjectsPerUserByStatus(1);
DROP PROCEDURE IF EXISTS `Get10ProjectsPerUserByStatus`;
注意:超出此处的问题,但实际上可以使用相同的逻辑将10项目限制作为存储过程的参数应用:
-- GET 10 PROJECTS PER USER WITH STATUS = 1
CALL GetProjectsPerUserByStatus(1, 10)
要执行此操作,您需要额外增加一个in-memory table
和另一个WHILE
循环
答案 4 :(得分:0)
这样的事情怎么样。
SELECT DISTINCT
users.id as expert_id,
users.firstname,
users.lastname,
myProjects.project_id,
myProjects.project_title,
myProjects.project_budget,
myProjects.project_created
FROM USERS RIGHT JOIN
expert_skills ON expert_skills.expert_id = users.id JOIN
project_skills ON project_skills.skill_id = expert_skills.skill_id JOIN
(SELECT P1.id as project_id,
P1.project_title,
P1.project_budget,
P1.created as project_created
FROM projects AS P1
WHERE P1.status = 1 AND
(SELECT COUNT(*)
FROM projects AS P2
WHERE P2.ID <= P1.ID) <= 10) AS myProjects ON myProjects.id = project_skills.project_id
答案 5 :(得分:0)
试试这个:
SELECT
users.id as expert_id, users.firstname,
projects.id as project_id, projects.project_title,
count(distinct users.id, ps2.project_id)
FROM USERS
JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN projects ON projects.id = project_skills.project_id
JOIN expert_skills es2 ON es2.expert_id = users.id
LEFT JOIN project_skills ps2 ON ps2.skill_id = es2.skill_id and ps2.project_id < projects.id
WHERE projects.status = 1
group by users.id, users.firstname, projects.id, projects.project_title
having count(distinct users.id, ps2.project_id) < 10
order by users.id, projects.id
假设10个项目的任何子集都有效,否则您将不得不调整标准。
为了清楚起见,我从选择中删除了一些字段。
答案 6 :(得分:0)
我认为你需要的是一个在内部有一个TOP 10的子查询。
像这样的东西(我真的没有得到查询,所以它可能不是你需要的)
SELECT users.id as expert_id, users.firstname, users.lastname, projs.*
FROM Users
RIGHT JOIN
(SELECT DISTINCT TOP 10 projects.id as project_id, projects.project_title, projects.project_budget, projects.created as project_created
FROM expert_skills
right JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
right JOIN projects ON projects.id = project_skills.project_id
WHERE projects.status = 1 ) projs ON expert_skills.expert_id = users.id
答案 7 :(得分:0)
大多数数据库都有办法要求查询的前X行。在DB2中,您可以使用以下语句返回前10行。
select * from tableName fetch first 10 rows only;
我相信在 MySql 中您使用限制关键字。
从tableName限制10中选择*;
如果您只想要拥有少于或等于10个项目的人,那么这不会起作用。我不清楚你是想得到那些有10个或更少项目的人,或者你是否想要只返回前10个项目。
答案 8 :(得分:0)
我会反向开始...首先获得项目,然后找到那些技能并拥有这些技能,按照“专家”的顺序计数器。从该结果集中,只需应用where子句以排除超出“截止”的范围。通过使用@ mysql变量并使用ORDER BY子句,您可以按专家ID的顺序获得返回的结果,因此在设置它们时,请查看是否为同一专家。如果是,请在序列计数器中添加一个。如果不同,则设置为零...那么,更新最后一位专家在结果集中的下一条记录上进行比较的人。
SELECT
PreQuery.expert_id,
PreQuery.firstname,
PreQuery.lastname,
PreQuery.Project_ID,
PreQuery.Project_Title,
PreQuery.Project_Budget,
PreQuery.Project_Created,
PreQuery.LastSeq
from
( SELECT DISTINCT
U.id as expert_id,
U.firstname,
U.lastname,
P.ID as Project_ID,
P.Project_Title,
P.Project_Budget,
P.Created as Project_Created,
@Seq := if( @LastExpert = U.ID, @Seq +1, 1 ) LastSeq,
@LastExpert := U.ID as IgnoreThis
from
Projects P
JOIN Project_Skills PS
ON P.ID = PS.Project_ID
JOIN Expert_Skills ES
ON PS.Skill_ID = ES.Skill_ID
JOIN Users U
ON ES.Expert_ID = U.ID,
(select @Seq := 0, @LastExpert = 0 ) SQLVars
where
P.Status = 1
order by
U.ID ) PreQuery
where
PreQuery.LastSeq < 11
答案 9 :(得分:-1)
这个怎么样......
SELECT users.id as expert_id, users.firstname, users.lastname, projects.id as project_id, projects.project_title, projects.project_budget, projects.created as project_created
FROM USERS
RIGHT JOIN expert_skills ON expert_skills.expert_id = users.id
JOIN project_skills ON project_skills.skill_id = expert_skills.skill_id
JOIN projects ON projects.id = project_skills.project_id
WHERE projects.status = 1
GROUP BY users.id as expert_id, users.firstname, users.lastname, projects.id as project_id, projects.project_title, projects.project_budget, projects.created
HAVING COUNT(*) < 10
这假设您的原始查询完全符合您的要求,但您只想将结果限制为返回的行少于10的位置。
可能没有其他帖子那么高效,我可能有错误的结束,但值得我2美分:)
答案 10 :(得分:-1)
我建议使用DENSE_RANK。我没有你的表结构,所以我创建了自己的,用户和项目表,具有1对多的关系。因此,为用户选择最后2个项目的查询是这样的(注意,您可以将其放入存储过程并使用该数字作为输入参数):
declare @numberOfProjects int
set @numberOfProjects = 3
;with topNProjects(userid, projectid, createdtutc, dense_rank)
as (
select p.userid, P.ProjectId, p.CreatedDtUtc, DENSE_RANK() OVER (PARTITION BY P.UserId ORDER BY P.ProjectId) AS DENSE_RANK
from DS_Project P
)
select userid, projectid, createdtutc from topNProjects
where dense_rank <= @numberOfProjects
order by projectid desc
DENSE_RANK有效地返回按字段分组的当前1 + 1之前的数字记录。
已编辑:我被指出这是MySQL的问题,而不是MSSQL。我没有安装MySQL,但显然排名还没有(或曾经)。我做了一些关于排名的搜索,我发现这个SO帖子可能有助于回答原始问题:How to perform grouped ranking in MySQL。因此,一旦添加排名,逻辑保持不变 - 选择排名低于每个用户所需项目数的所有记录。