sql >> Databasteknik >  >> RDS >> Sqlserver

Är det möjligt att lagra värdet för en utvald kolumn och använda den för nästa?

Du behöver CROSS APPLY här kan det referera till yttre referenser, inga irriterande underfrågor eller CTE:er behövs:

select col1, col2
from table1 as outer_table

-- can also have multi-row values
cross apply (values (complex_expression_1) ) as v1 (col1)
cross apply (values (expression_referring_to_col1) ) as v2 (col2)

-- alternate syntax, select without from returns a single row
cross apply (select complex_expression_1 as col1 ) AS v1
cross apply (select expression_referring_to_col1 as col2 ) as v2

-- you can also do anything you like in there, can be one or multiple rows
cross apply (
    select complex_expression_1 as col1 
    from othercomplexjoin as o
    where o.join_column = outer_table.join_column
) AS v1

Några fler knep du kan göra med APPLY :

1. Topp 1 per grupp av underordnade bord:

En klassisk lösning på "topp 1 per grupp" är att använda row_number() . Detta kan ofta resultera i enorma skanningar, särskilt när antalet distinkta yttre värden är litet i förhållande till den underordnade tabellen.

select
    o.id,
    lastPayment.Date
from order_header as o
join
( select *, row_number() over (partition by order_id order by date desc) as rn
 from payments
) as lastPayment on ...
where lastPayment.rn = 1

Istället kan vi göra:

select
    o.id,
    lastPayment.Date
from order_header as o
cross apply
( select top (1) *
 from payments as p
 where p.order_id = o.id
 order by date desc
) as lastPayment

Obs:OUTER APPLY ersätter begreppsmässigt en vänsterkoppling, dvs. returnerar nollvärden istället för inga rader.

2. Avpivotering

select
    o.id,
    customer.*
from order_header as o
cross apply ( values    -- This returns two rows for every order_header
    ( 'DeliveryCustomer', o.deliveryCustomer ),
    ( 'billingCustomer', o.billingCustomer )
) as customer (type, name)

3. Exploderar ut en rad ett varierande antal gånger:

Säg att vi vill ta ett belopp och dela upp det i olika rader. Om amount <= 50 sedan en rad med amount , om > 50 sedan två rader, en på 50 och en av resten:

select t.id, v.amount
from table as t
cross apply (
    select case when amount > 50 then 50 else amount end as amount
    union all
    select amount - 50   -- note this row will not appear if amount < 50
    where amount > 50
) v


  1. Ska jag indexera primärnyckelkolumner i Oracle

  2. Vad är skillnaden mellan USER() och SYS_CONTEXT('USERENV','CURRENT_USER')?

  3. Oracle:Dagar mellan två datum och Exkludera veckodagar hur man hanterar negativa tal

  4. Lägg till WHERE-satser till SQL dynamiskt / programmatiskt