Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Възможно ли е да се съхрани стойността на една колона за избор и да се използва за следващата?

Трябва ви CROSS APPLY тук може да се отнася до външни препратки, не са необходими досадни подзаявки или CTE:

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

Още няколко трика, които можете да правите с APPLY :

1. Топ 1 за група дъщерна маса:

Класическо решение за „първите 1 на група“ е да използвате row_number() . Това често може да доведе до огромно сканиране, особено когато броят на отделните външни стойности е малък спрямо дъщерната таблица.

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

Вместо това можем да направим:

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

Забележка:OUTER APPLY концептуално замества лявото присъединяване, т.е. връща нулеви стойности вместо никакви редове.

2. Отмяна на завъртанета

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. Разгръщане на ред променлив брой пъти:

Да кажем, че искаме да вземем сума и да я разделим на различни редове. Ако amount <= 50 след това един ред amount , ако > 50 след това два реда, един от 50 и един от останалите:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Не може да се свърже с локален хост, но може с името на компютъра в SQL Server 2008

  2. Името на колоната или броят на предоставените стойности не съответстват на дефиницията на таблицата

  3. Върнете основния тип данни от стойност на SQL_Variant в SQL Server

  4. Колоната е невалидна в списъка за избор, защото не се съдържа нито в агрегатна функция, нито в клаузата GROUP BY

  5. Актуализиране на пощенски акаунт в база данни в SQL Server (T-SQL)