我有 2 个表
TicketHeaders TH
>amount | |
---|---|
1 | >600 |
2 | ;">900 |
3 | 400 |
SELECT TH.ticketID, TH.Amount, COALESCE(TB_M.SellerName, TB_T.SellerName)
FROM TH
LEFT JOIN TB TB_M ON TH.ticketID = TB_M.ticketID AND TB_M.SellerType = 'Manager'
LEFT JOIN TB TB_T ON TH.ticketID = TB_T.ticketID AND TB_T.SellerType <> 'Manager'
根据所述的 2.5 版,您似乎无法使用row_number()
解决方案。您可以使用单个内部联接来解决此问题。我不知道避免额外加入火鸟是否有任何好处。
select ticketID, min(Amount) as Amount,
case min(case SellerType when 'Manager' then 1 else 2 end) when 1
then min(case SellerType = 'Manager' then SellerName end)
else min(case SellerType <> 'Manager' then SellerName end)
end SellerName
from TH th inner join TB tb on tb.ticketID = th.ticketID
group by ticketID
另一个好处是,这将适用于不同卖家的更大层次结构(通过添加新案例)。但是,如果在一个级别上有多个卖家,则不起作用。
在这种情况下我会使用 row_number():
with _cte as (
SELECT TH.ticketID,
TH.Amount,
TB.SellerName,
row_number() over (partition by TH.ticketID order by case when SellerType = 'Manager' then 0 else 1 end) as rn
FROM TH
LEFT JOIN TB ON TH.ticketID = TB.ticketID
)
select ticketID, Amount, SellerName
from _cte
where rn = 1
A.S.我认为您的问题尚未明确定义:
我只需要为该特定工单选择经理
如果有很多行,但有两个或更多经理怎么办?零经理?没有经过深思熟虑,就像保证SQL服务器永远不会允许插入此类数据一样,这是一个等待发生的错误。
我还认为SellerType
最好是一个整数字段,一个Seller_types
字典表的外键——既是因为整数字段更容易index
编辑和比较join
表,也因为这样可以让你以后随心所欲地重命名"功能角色"(或者像你被老板做的那样), 无需更改任何内容:您的Seller_types
可以有额外的列,例如整数role_priority
,甚至类似于max_persons_of_type_in_one_ticket
(例如,您的老板可能会决定一张票上可以有两个经理,或者一个经理和一个副经理,然后不超过四个实习生)。
但回到问题,还有一种方法可以做到这一点。它实际上会为表中的每一行运行correlated sub-query
TicketHeaders
因此,如果您执行数千行的"长"选择,它可能会更慢。特别是如果你保留了 Firebird 的默认小内存缓存(请参阅有关配置 Firebird 和 ib-aid.com 上宽松配置的文章)。
另一方面,它类似于"做一次就忘记",使您的查询更简单,从而减少您将来出错的机会。在短(100 行或更少)查询中,速度惩罚可能不明显。而且,如果您根本不查询该新列,也不会受到任何惩罚(您不在生产中使用select *
查询,是吗?
所以,代码,最后:db<>小提琴在这里
create table Ticket_Headers ( ticket_id integer primary key, amount integer not null )
create table Ticket_Body ( ticket_id integer REFERENCES Ticket_Headers(ticket_id) ON DELETE CASCADE ON UPDATE CASCADE, Seller_Name varchar(20) not null, Seller_Type varchar(20) not null, CONSTRAINT TicketBody_PK PRIMARY KEY (ticket_id, Seller_Name) )
create index idx_TicketBody_Type on Ticket_Body(Seller_Type)
insert into Ticket_Headers select 1, 600 from rdb$database union all select 2, 900 from rdb$database union all select 3, 400 from rdb$database
受影响的 3 行
insert into Ticket_body select 1, 'Karen', 'Manager' from rdb$database union all select 1, 'James', 'Trainee' from rdb$database union all select 2, 'John', 'Manager' from rdb$database union all select 3, 'James', 'Trainee' from rdb$database
受影响的 4 行
select * from Ticket_Headers
TICKET_ID |量 --------: |-----: 1 | 600 2 | 900 3 | 400
select * from Ticket_Body
TICKET_ID |SELLER_NAME |SELLER_TYPE --------: |:---------- |:---------- 1 |凯伦 |经理 1 |詹姆斯 |实习 2 |约翰 |经理 3 |詹姆斯 |实习生
select * from Ticket_Headers TH, Ticket_Body TB where TH.ticket_id = TB.ticket_ID
TICKET_ID |金额 |TICKET_ID |SELLER_NAME |SELLER_TYPE --------: |-----: |--------: |:---------- |:---------- 1 | 600 | 1 |凯伦 |经理 1 | 600 | 1 |詹姆斯 |实习 2 | 900 | 2 |约翰 |经理 3 | 400 | 3 |詹姆斯 |实习生
alter table Ticket_Headers add Seller_Top computed by ( -- this parenthesis is required by COMPUTED BY SQL syntax ( -- this parenthesis is required to coerce SELECT from query to expression select First(1) TB.Seller_Name from Ticket_Body TB where TB.ticket_id = Ticket_Headers.ticket_id order by TB.Seller_type /* Descending - if other order to be needed */ ) )
select * from Ticket_Headers
TICKET_ID |金额 |SELLER_TOP --------: |-----: |:--------- 1 | 600 |凯伦 2 | 900 |John 3 | 400 |詹姆斯
上述Seller_types.role_priority
将更加灵活,因此对于这样的order-by
来说是面向未来的方法。