通过连接选择不同

时间:2012-10-05 13:54:02

标签: ruby-on-rails ruby postgresql

我们有2个表:用户和状态

状态表有user_id,status和occured_on。状态为“已删除”或“已添加”,而occured_on是用户被删除或添加的日期。

我需要当前添加的用户。也就是说,所有(不同的)用户的最新状态记录都是“添加”。

我正在使用Rails,并尝试过:

User
  .joins(:statuses)
  .where('statuses.status = ?', 'added')
  .order('statuses.occured_on DESC')
  .uniq

转换为SQL:

SELECT DISTINCT users.* 
FROM users
INNER JOIN statuses
ON statuses.user_id = users.id 
WHERE statuses.status = 'added' 
ORDER BY statuses.occured_on DESC

这给了我错误:

PG::Error: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list
   LINE 1: ...statuses.status = 'added') ORDER BY statuses.oc...

我很高兴知道可行的Rails代码或直接的SQL。

另外,如果可能的话,我不想选择子选项。

2 个答案:

答案 0 :(得分:1)

Concider以下数据库架构更改:

StatusTable:

StatusId
Status
UserId
ActiveFrom
ActiveTo

之后您可以添加其他支票,例如:

CONSTRAINT chk_from_to CHECK (ActiveFrom <= ActiveTo)

然后你的查询看起来像:

   SELECT users.*
   FROM users 
   JOIN statuses ON UserId = users.user_id AND ActiveFrom < CURRENT_TIMESTAMP AND ActiveTo > CURRENT_TIMESTAMP
   WHERE statuses.Status = 'active'

使用这种结构,您可能需要更改状态的更改方式,但根据我自己的经验,此结构更灵活,更易于查询。

答案 1 :(得分:0)

SELECT * FROM users INNER JOIN statuses ON users.id=statuses.user_id WHERE statuses.status='added' ORDER BY statuses.occured_on

在澄清之后,我认为架构并不是为您的目标而设计的。您能否澄清为什么要包含该表中包含的状态更改历史记录?我的一般方法是活动用户应该包含在名为projects_users的表中,其中包含project_id,user_id。当它们被“移除”时,应该从该表中删除它们。操作的日志 - 在项目中添加和删除用户 - 应存储在单独的表中。

根据您当前的设计,我没有很好的方法来编写此查询。即使你修复了错误,这在MySQL中也没有错误运行(这正是你所拥有的)

SELECT DISTINCT `users`.* FROM `users`
INNER JOIN `projects_users`
ON `users`.`id`=`projects_users`.`user_id`
WHERE `status`='added'
ORDER BY `projects_users`.`occured_on` DESC

它仍然不会得到正确的结果。 ORDER BY子句只会让您获得“添加”的最新更改,但不能保证没有更新的“已删除”操作。要做到这一点,你需要将每个最近添加的记录的日期与最近删除的记录的日期进行比较,对于每个用户来说,这是一场噩梦。