sql >> Database >  >> RDS >> Sqlserver

Mogelijk om de waarde van een geselecteerde kolom op te slaan en te gebruiken voor de volgende?

Je hebt CROSS APPLY . nodig hier kan het verwijzen naar externe referenties, geen vervelende subquery's of CTE's nodig:

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

Nog wat trucs die je kunt doen met APPLY :

1. Top 1 per groep kindertafels:

Een klassieke oplossing voor de "top 1 per groep" is het gebruik van row_number() . Dit kan vaak resulteren in enorme scans, vooral wanneer het aantal verschillende buitenste waarden klein is ten opzichte van de onderliggende tabel.

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

In plaats daarvan kunnen we doen:

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

Opmerking:OUTER APPLY vervangt conceptueel een left join, d.w.z. retourneert nulls in plaats van geen rijen.

2. Draaien ongedaan maken

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. Een rij een variabel aantal keren laten exploderen:

Stel dat we een bedrag willen nemen en het in verschillende rijen willen splitsen. Als het amount <= 50 dan een rij van amount , als > 50 dan twee rijen, een van de 50 en een van de rest:

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. Wat is het verschil tussen MS Access en SQL?

  2. Hoe de uitvoer van DBMS_OUTPUT.PUT_LINE omleiden naar een bestand?

  3. Hoe kan ik de bestaande kolom als identiteit in PostgreSQL 11.1 wijzigen?

  4. Geen SQL-impasse door ontwerp - enige coderingspatronen?