【问题标题】:Join and fetch columns based on priority根据优先级加入和获取列
【发布时间】:2021-12-15 21:47:42
【问题描述】:
CREATE TABLE orders
(
    product CHAR(3), 
    yr CHAR(4)
);

INSERT INTO orders VALUES ('a', '2019');
INSERT INTO orders VALUES ('m', '2019');

CREATE TABLE customers
(
    cus_name CHAR(20), 
    columnX CHAR(3), 
    columnY CHAR(3),
    price INT
);

INSERT INTO customers VALUES ('john', 'b', 'a', 100);
INSERT INTO customers VALUES ('brad', 'a', 'd', 200);
INSERT INTO customers VALUES ('chris', 'm', 'y', 200);
INSERT INTO customers VALUES ('Luis', 'r', 'm', 200);

我想根据orders 表中的product 列将订单表与客户表连接起来。

我想根据每个产品的 columnYcolumnX 列获取一个 price

columnY 应优先考虑。如果产品存在于columnY 中,则从该行获取价格。

如果不存在,则检查columnX 并获取该价格。

下面带有 OR 操作的查询给了我两行,但我只想要第一行 cus_name 作为 John

select *
from orders a
left join customers c on a.product = c.columnY 
                      or a.product = c.columnX
product yr cus_name columnX columnY price
a 2019 john b a 100
a 2019 brad a d 200
m 2019 chris m y 200
m 2019 Luis r m 200

预期的输出是:

product yr cus_name columnX columnY price
a 2019 john b a 100
m 2019 luis r m 200

提前致谢

为清楚起见进行编辑:每个产品在 columnXcolumnY 中只会出现一次,即 ColumnYColumnX 不能有多个产品“a”

编辑 2 - 在订单表中包含多个产品。

【问题讨论】:

  • 选择约翰而不是布拉德的标准是什么?也许是一个简单的TOP 1
  • 是的,在上面的示例中,条件是每当产品“a”首先出现在客户表的 Y 列中时
  • 如果 Y 中的产品存在 2 行怎么办?

标签: sql sql-server tsql join


【解决方案1】:

使用CASE expression,您可以按定义的优先级排序,然后使用TOP 1 进入第一行。

但这并不能解决有 2 行与您的优先级匹配的问题。

select top 1 *
from orders a
left join customers c on 
    a.product = c.columnY 
    or a.product = c.columnX
order by case when a.product = c.columnY then 1 else 0 end desc;

您的说明需要多种产品,您需要一个完全不同的解决方案。一个常见的解决方案是使用row_number() 窗口函数来查找每个产品的第一行,例如

with cte as (
    select *
        -- Use the same ordering as before, but now partitioned by product.
        , row_number() over (partition by a.product order by case when a.product = c.columnY then 1 else 0 end desc) rn
    from #orders a
    left join #customers c on 
        a.product = c.columnY 
        or a.product = c.columnX
)
select product, yr, cus_name, columnX, columnY, price
from cte
-- Only pick the first result, ordered by our priority, per product
where rn = 1
order by product, yr, cus_name;

返回:

product yr cus_name columnX columnY price
a 2019 john b a 100
m 2019 Luis r m 200

【讨论】:

  • 我必须修改此代码以获得每个产品的前 1 名。按产品分组并获得每个产品的前 1 名。非常感谢
  • 很抱歉,感谢您让我知道。我刚刚重新更新了它。希望我能更好地在堆栈溢出中提问
  • 完美。这有效
【解决方案2】:

我根据 cmets 更改了@Dale 答案并准备了示例(不知道如果有多个年份条目是否有帮助)

Declare @orders TABLE(product CHAR(3), yr CHAR(4));
INSERT INTO @orders VALUES ('a', '2019');
INSERT INTO @orders VALUES ('a', '2020');

Declare @customers TABLE(cus_name CHAR(20), columnX CHAR(3), columnY CHAR(3),price int );
INSERT INTO @customers VALUES ('john', 'b','a',100);
INSERT INTO @customers VALUES ('brad', 'a','d',200);

Select *
from @orders a
left join @customers c on 
    case when a.product = c.columnY then a.product else c.columnY end = a.product
    --a.product = c.columnY 
 --   or a.product = c.columnX
order by case when a.product = c.columnY then 1 else 0 end desc;

结果

如果我们删除 2020 条目(与当前情况相同,则结果将是)

【讨论】:

    【解决方案3】:

    我会通过“Intersect”找到“ColumnY”列的所有目标值,然后将它们用作过滤器。

    Select orders.product, orders.yr, customers.cus_name, customers.columnX, customers.columnY, customers.price
    From customers Inner Join orders On (customers.columnY=orders.product)
    Where columnY In (Select columnY From customers 
                      Intersect
                      Select columnX From customers)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-04
      • 1970-01-01
      • 2012-08-08
      • 1970-01-01
      • 2014-08-05
      • 2021-07-06
      相关资源
      最近更新 更多