Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Ist es möglich, den Wert einer ausgewählten Spalte zu speichern und für die nächste zu verwenden?

Sie benötigen CROSS APPLY hier kann auf äußere Referenzen verwiesen werden, es werden keine lästigen Unterabfragen oder CTEs benötigt:

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

Einige weitere Tricks, die Sie mit APPLY ausführen können :

1. Top 1 pro Gruppe von untergeordneten Tabellen:

Eine klassische Lösung für die „Top 1 pro Gruppe“ ist die Verwendung von row_number() . Dies kann oft zu umfangreichen Scans führen, insbesondere wenn die Anzahl unterschiedlicher äußerer Werte im Vergleich zur untergeordneten Tabelle klein ist.

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

Stattdessen können wir Folgendes tun:

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

Hinweis:OUTER APPLY ersetzt konzeptionell einen linken Join, d.h. gibt Nullen statt keine Zeilen zurück.

2. Unpivoting

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. Eine Reihe unterschiedlich oft auflösen:

Angenommen, wir möchten einen Betrag nehmen und ihn in verschiedene Zeilen aufteilen. Wenn der amount <= 50 dann eine Zeile mit amount , wenn > 50 dann zwei Reihen, eine von 50 und eine von den anderen:

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