【问题标题】:Select the first matching row选择第一个匹配的行
【发布时间】:2012-03-19 06:38:12
【问题描述】:

我有一个表格“tbl”,看起来像这样:

prod | cust | qty
p1   | c1   | 5
p1   | c2   | 10
p2   | c1   | 2
p3   | c2   | 8

我需要的是一份不同的产品和客户对列表,但如果产品出售给多个客户,则只需要第一个客户。换句话说,结果需要如下所示:

prod | cust
p1   | c1   
p2   | c1   
p3   | c2   

我已经尝试了所有我能想到的方法,但我不能完全得到正确的结果。显然 distinct 和 group by 都不起作用(单独),因为它们都会返回 p1, c2 行。

我发现这个question 非常接近,但我不知道如何重新编写它来让它做我需要的事情。

最重要的是,这一切目前需要在 Access 2007 或更高版本中运行,但在未来某个时候,它也需要在 MySQL 中运行。

对将结果加入客户表的任何人都给予额外的奖励,以便我可以从客户代码中查找人类可读的名称,例如c1 => Fred Bloggs 扳手

【问题讨论】:

  • 如何定义“第一客户”?是否有一个日期字段可以明确说明您没有显示?
  • 我将“first”定义为查询返回的任何一个 - 我很乐意返回 p1,c1 或 p1,c2 我只是无法同时返回两者(因为产品代码正在另一个连接中使用,我不希望重复)。表 tbl 中没有其他有用的字段。
  • 好的,我在发布答案后阅读了这条评论——这没有意义——你想要“第一个”客户,但你实际上并不关心“第一个”客户实际上是谁是或如何确定的?我不是在写你的要求,但你真的想要随着时间的推移基本上随机的结果?!?
  • 好吧,我应该说任意单个客户。我完全意识到客户会随着时间的推移而改变,我不喜欢它,但我必须忍受它。基本上,我使用此查询中的产品密钥加入的另一个表不包含任何客户信息。行仅由产品密钥标识,我必须报告的所有客户的总数。客户希望看到客户和产品的突破,但这是不可能的 - 他们没有数据 - 所以我们被要求只报告任何针对产品的有效客户。

标签: sql ms-access


【解决方案1】:

核心问题:

SELECT prod, MIN(cust)
FROM yourTable
GROUP BY prod

对于“奖金”:

SELECT T.prod,
       T.cust,
       YC.SomeCustomerAttribute1,
       YC.SomeCustomerAttribute2
FROM (
      SELECT prod, MIN(cust) AS first_cust
      FROM yourProducts
      GROUP BY prod
) AS T
JOIN yourCustomers AS YC ON YC.cust = T.first_cust

【讨论】:

  • +1 虽然我开始怀疑 OP 只是想要SELECT DISTINCT prod FROM table
  • 非常感谢您的回答,找到我想要的。我从来没有想过使用 min.
【解决方案2】:

我将不得不假设您有某种标识符来指示谁是“第一”。日期列或身份列或其他内容。

在我的示例中,我使用 order_id 标识列完成了此操作。

CREATE TABLE products (
    order_id MEDIUMINT NOT NULL AUTO_INCREMENT,
    prod char(2), 
    cust char(2),
    qty int,
    PRIMARY KEY (order_id)
);

INSERT INTO products (prod, cust, qty) VALUES
   ('p1', 'c1', 5),
   ('p1', 'c2', 10),
   ('p2', 'c1', 2),
   ('p3', 'c2', 8);

然后让你的价值观运行:

select p1.prod, p1.cust, p1.qty
from products p1
where not exists (select * from products p2
              where p1.prod = p2.prod
              and p2.order_id < p1.order_id)

您在每行的哪个位置检查是否有其他客户比您更早下单。如果有更早的订单,则不要列出此行。 (因此not exists

这是 mysql 语法,顺便说一句,你说你要迁移到它。 (访问专家必须对此进行适当的编辑。)

现在,如果您没有一列来标识输入订单的顺序,那么您需要一列。任何依赖于基于插入顺序的隐式 row_numbering 的方案最终都会崩溃,因为不能保证“第一行”保持不变。

【讨论】:

  • 据我所知 MS Access 不支持exists
  • 您可能对访问是正确的——我使用了很多数据库,但不是访问,我认为它是 ANSI,但显然不是。应该把 mysql 的限定词放在更高的位置(他说他最终需要)。我仍然会强调我的讨论,要真正做任何事情,他需要某种序列/日期时间标识符。但既然他只是想要一个随机的结果,那就随便吧。 . .
  • 愚蠢的我,我想走那条路,但用谷歌搜索了一下,似乎它不受支持。我现在看到了。在我说话之前我应该​​更努力地谷歌!
【解决方案3】:

如果您只想要第一个结果,请将LIMIT 1 添加到您的查询中,或者使用SELECT DISTINCT 来获得唯一的结果。

至于您的加入,请查看:

SELECT * FROM TableA
INNER JOIN TableB
ON TableA.name = TableB.name

这将从 tableA 和 tableB 中获取具有匹配 name 的所有行。

编辑 J Cooper 是对的,ms-access 没有与LIMIT 等效的对象。最接近的是TOP,但我认为这不会有帮助。抱歉,从大学开始就没有使用过访问权限。

【讨论】:

  • 我不想只是第一行。我也想要 p2,c1 和 p3,c2 行。限制会导致只返回 p1,c1。
  • 我很确定 ms-access 不支持LIMIT
【解决方案4】:

"First" 和 min() 不一样。如果你真的想先试试这个:

declare @source table
(
    prod varchar(10),
    cust varchar(10),
    qty int
)

insert into @source (prod, cust, qty) values ('p1', 'c1', 5)
insert into @source (prod, cust, qty) values ('p1', 'c2', 10)
insert into @source (prod, cust, qty) values ('p2', 'c1', 2)
insert into @source (prod, cust, qty) values ('p3', 'c2', 8)

select * from @source

declare @target table
(
    prod varchar(10),
    cust varchar(10),
    qty int
)

insert into @target (prod)
select distinct prod from @source

update @target
set
    cust = s.cust,
    qty = s.qty
from @source s
join @target t on t.prod = s.prod

select * from @target

【讨论】:

  • 这是 SQL Server 代码,T-SQL。源数据库和目标数据库都不是 SQL Server 数据库。此代码也不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多