ฉันควรใช้การสมัครไขว้กับการเข้าร่วมวงใน


925

วัตถุประสงค์หลักในการใช้CROSS APPLYคืออะไร

ฉันได้อ่าน (ผ่านทางโพสต์บนอินเทอร์เน็ต) ที่cross applyมีประสิทธิภาพมากขึ้นเมื่อเลือกผ่านชุดข้อมูลขนาดใหญ่หากคุณแบ่งพาร์ติชัน (เพจมาถึงใจ)

ฉันก็รู้ว่าCROSS APPLYไม่จำเป็นต้องมี UDF เป็นตารางขวา

ในINNER JOINข้อความค้นหาส่วนใหญ่(ความสัมพันธ์แบบหนึ่งต่อหลายคน) ฉันสามารถเขียนใหม่เพื่อใช้งานCROSS APPLYได้ แต่จะให้แผนการดำเนินการเทียบเท่าเสมอ

ทุกคนสามารถให้ฉันเป็นตัวอย่างที่ดีของเมื่อCROSS APPLYสร้างความแตกต่างในกรณีที่INNER JOINจะทำงานได้ดี?


แก้ไข:

นี่เป็นตัวอย่างเล็กน้อยที่แผนการดำเนินการเหมือนกันทุกประการ (แสดงให้ฉันดูว่าพวกเขาแตกต่างกันที่ไหนและcross applyเร็วกว่า / มีประสิทธิภาพมากขึ้น)

create table Company (
    companyId int identity(1,1)
,   companyName varchar(100)
,   zipcode varchar(10) 
,   constraint PK_Company primary key (companyId)
)
GO

create table Person (
    personId int identity(1,1)
,   personName varchar(100)
,   companyId int
,   constraint FK_Person_CompanyId foreign key (companyId) references dbo.Company(companyId)
,   constraint PK_Person primary key (personId)
)
GO

insert Company
select 'ABC Company', '19808' union
select 'XYZ Company', '08534' union
select '123 Company', '10016'


insert Person
select 'Alan', 1 union
select 'Bobby', 1 union
select 'Chris', 1 union
select 'Xavier', 2 union
select 'Yoshi', 2 union
select 'Zambrano', 2 union
select 'Player 1', 3 union
select 'Player 2', 3 union
select 'Player 3', 3 


/* using CROSS APPLY */
select *
from Person p
cross apply (
    select *
    from Company c
    where p.companyid = c.companyId
) Czip

/* the equivalent query using INNER JOIN */
select *
from Person p
inner join Company c on p.companyid = c.companyId

50
ฉันรู้ว่านี่คือตัวเลือกของฉัน แต่ 'นักแสดง' เป็นคำที่แน่นอนที่สุด มันไม่เกี่ยวข้องกับประสิทธิภาพ
Rire1979

2
มันมีประโยชน์มากสำหรับ sql xquery ตรวจสอบนี้
ARZ

3
ดูเหมือนว่าการใช้ "การเข้าร่วมวงใน" จะใกล้เคียงกับการข้ามมาก ฉันขอให้ตัวอย่างของคุณมีรายละเอียดซึ่งคำใบ้การเข้าร่วมนั้นเท่ากัน เพียงแค่บอกว่าเข้าร่วมอาจส่งผลให้ภายใน / ลูป / ผสานหรือแม้กระทั่ง "อื่น ๆ " เพราะมันอาจจัดเรียงใหม่กับการรวมอื่น ๆ
crokusek

3
เมื่อการเข้าร่วมจะสร้างแถวจำนวนมาก แต่คุณจะต้องประเมินการเข้าร่วมครั้งละหนึ่งแถวเท่านั้น ฉันมีกรณีที่ฉันต้องการตัวเองเข้าร่วมในตารางที่มีมากกว่า 100 ล้านแถวและมีหน่วยความจำไม่ง่ายพอ ดังนั้นฉันจึงใช้เคอร์เซอร์เพื่อลดขนาดหน่วยความจำลง จากเคอร์เซอร์ฉันไปใช้เป็น crossprint หน่วยความจำที่ยังจัดการและเร็วกว่าเคอร์เซอร์ 1/3
paparazzo

10
CROSS APPLYมีการใช้งานที่ชัดเจนในการอนุญาตให้ชุดพึ่งพาอื่น (ต่างจากตัวJOINดำเนินการ) แต่ไม่ได้มาโดยไม่มีค่าใช้จ่าย: มันทำงานเหมือนฟังก์ชันที่ทำงานกับสมาชิกแต่ละตัวของชุดซ้ายดังนั้นในแง่ของ SQL Server ดำเนินการเสมอLoop Joinซึ่งแทบไม่เคยเป็นวิธีที่ดีที่สุดในการเข้าร่วมชุด ดังนั้นการใช้งานAPPLYเมื่อคุณต้องการ JOINแต่ไม่ได้มีการใช้มากเกินไปมันกับ
Gerardo Lima

คำตอบ:


667

ทุกคนสามารถให้ฉันเป็นตัวอย่างที่ดีได้เมื่อครอสส์นำไปใช้สร้างความแตกต่างในกรณีที่ INNER JOIN ทำงานได้ดีหรือไม่?

ดูบทความในบล็อกของฉันสำหรับการเปรียบเทียบประสิทธิภาพโดยละเอียด:

CROSS APPLYทำงานได้ดีขึ้นในสิ่งที่ไม่มีJOINเงื่อนไขอย่างง่าย

อันนี้เลือก3ระเบียนสุดท้ายจากt2สำหรับแต่ละระเบียนจากt1:

SELECT  t1.*, t2o.*
FROM    t1
CROSS APPLY
        (
        SELECT  TOP 3 *
        FROM    t2
        WHERE   t2.t1_id = t1.id
        ORDER BY
                t2.rank DESC
        ) t2o

ไม่สามารถกำหนดสูตรได้อย่างง่ายดายด้วยINNER JOINเงื่อนไข

คุณอาจทำอะไรเช่นนั้นโดยใช้CTEฟังก์ชั่นและหน้าต่าง:

WITH    t2o AS
        (
        SELECT  t2.*, ROW_NUMBER() OVER (PARTITION BY t1_id ORDER BY rank) AS rn
        FROM    t2
        )
SELECT  t1.*, t2o.*
FROM    t1
INNER JOIN
        t2o
ON      t2o.t1_id = t1.id
        AND t2o.rn <= 3

แต่สิ่งนี้สามารถอ่านได้น้อยลงและอาจมีประสิทธิภาพน้อยลง

ปรับปรุง:

เพียงแค่ตรวจสอบ

masterเป็นตารางประมาณ20,000,000ระเบียนกับบนPRIMARY KEYid

แบบสอบถามนี้:

WITH    q AS
        (
        SELECT  *, ROW_NUMBER() OVER (ORDER BY id) AS rn
        FROM    master
        ),
        t AS 
        (
        SELECT  1 AS id
        UNION ALL
        SELECT  2
        )
SELECT  *
FROM    t
JOIN    q
ON      q.rn <= t.id

ทำงานเกือบ30วินาทีในขณะที่อันนี้:

WITH    t AS 
        (
        SELECT  1 AS id
        UNION ALL
        SELECT  2
        )
SELECT  *
FROM    t
CROSS APPLY
        (
        SELECT  TOP (t.id) m.*
        FROM    master m
        ORDER BY
                id
        ) q

เป็นทันที


2
ดูจุดสิ้นสุดของลิงก์ของ Ariel แบบสอบถาม row_number () เป็นสิ่งที่ดีและไม่จำเป็นต้องมีการเข้าร่วม ดังนั้นฉันไม่คิดว่าฉันควรใช้ cross Apply สำหรับสถานการณ์นี้ (เลือก top 3, แบ่งพาร์ติชันโดย t1.id)
Jeff Meatball Yang

375
แม้ว่านี่จะเป็นคำตอบที่ได้รับความนิยมมากที่สุด แต่ฉันไม่คิดว่ามันจะตอบคำถามที่แท้จริงว่า "อะไรคือวัตถุประสงค์หลักในการใช้ CROSS APPLY?" วัตถุประสงค์หลักคือเพื่อเปิดใช้งานฟังก์ชันตารางพร้อมพารามิเตอร์ที่จะดำเนินการหนึ่งครั้งต่อแถวจากนั้นเข้าร่วมกับผลลัพธ์
MikeKulls

5
@ ไมค์: คุณเรียก a TVFด้วยINNER JOINอย่างไร
Quassnoi

15
@ MikeKulls ใช่ แต่ OP ไม่ได้ถามถึงจุดประสงค์หลักของการใช้CROSS APPLYเขาถามว่าเมื่อไรที่จะเลือกมันINNER JOINเมื่อไหร่มันจะใช้ได้ดีเช่นกัน
ErikE

8
มันอาจจะคุ้มค่าที่จะกล่าวถึงว่าสิ่งนี้เรียกว่าlateral joinSQL แบบมาตรฐาน (ANSI)
a_horse_with_no_name

198

cross applyinner joinบางครั้งก็ช่วยให้คุณสามารถทำสิ่งที่คุณไม่สามารถทำอะไรกับ

ตัวอย่าง (ข้อผิดพลาดทางไวยากรณ์):

select F.* from sys.objects O  
inner join dbo.myTableFun(O.name) F   
on F.schema_id= O.schema_id

นี่เป็นข้อผิดพลาดทางไวยากรณ์เนื่องจากเมื่อใช้กับinner joinฟังก์ชันตารางสามารถรับตัวแปรหรือค่าคงที่เป็นพารามิเตอร์เท่านั้น (เช่นพารามิเตอร์ของฟังก์ชันตารางไม่สามารถขึ้นอยู่กับคอลัมน์ของตารางอื่น)

อย่างไรก็ตาม:

select F.* from sys.objects O  
cross apply ( select * from dbo.myTableFun(O.name) ) F  
where F.schema_id= O.schema_id

สิ่งนี้ถูกกฎหมาย

แก้ไข: หรืออีกทางหนึ่งคือไวยากรณ์ที่สั้นกว่า: (โดย ErikE)

select F.* from sys.objects O  
cross apply dbo.myTableFun(O.name) F
where F.schema_id= O.schema_id

แก้ไข:

หมายเหตุ: Informix 12.10 xC2 + มีตารางด้านหลังและ Postgresql (9.3+) มีแบบสอบถามย่อยด้านข้างซึ่งสามารถใช้กับเอฟเฟกต์ที่คล้ายกันได้


11
ฉันคิดว่านี่เป็นเหตุผลเบื้องหลังว่าทำไมเราถึงใช้การไขว้กัน หากคุณตรวจสอบลิงค์ด้านล่างนี้เป็นสิ่งแรกที่ MS พูดเกี่ยวกับการใช้งานข้าม อาจมีประโยชน์อื่น ๆ แต่ฉันคิดว่านี่คือเหตุผลที่เปิดตัว หากไม่มีฟังก์ชันตารางจะไม่สามารถใช้งานได้ในหลายสถานการณ์ technet.microsoft.com/en-us/library/ms175156.aspx
MikeKulls

ใช้ข้ามยังสร้างแผนการดำเนินการที่ดีเมื่อควบคู่กับฟังก์ชั่นตารางแบบอินไลน์ในขณะที่ยังคงรักษาความเป็นโมดูลที่จำเป็นมาก
นูเรตอิน

14
ไม่มีความจำเป็นภายในSELECT โปรดลองCROSS APPLY CROSS APPLY dbo.myTableFun(O.name) F
ErikE

1
@ErikE แน่ใจว่าคุณสามารถใช้ไวยากรณ์ที่มีความยืดหยุ่นน้อยกว่าเพื่อใช้ข้ามได้ตลอดเวลา ฉันแสดงรุ่นทั่วไปที่บางครั้งคุณสามารถใช้เพื่อหลีกเลี่ยงการนำคอลัมน์ไปคำนวณได้ยาก
nurettin

2
@Bolu Inner join จะไม่ทำงานหากพารามิเตอร์ของฟังก์ชันตารางขึ้นอยู่กับคอลัมน์ของตารางอื่น (aka การอ้างอิงภายนอก) ในตัวเลือกภายนอก มันจะทำงานถ้าพารามิเตอร์ฟังก์ชั่นตารางเป็นตัวอักษรหรือตัวแปร ใช้ข้ามจะทำงานในทั้งสองกรณี
nurettin

175

พิจารณาว่าคุณมีสองตาราง

ตารางหลัก

x------x--------------------x
| Id   |        Name        |
x------x--------------------x
|  1   |          A         |
|  2   |          B         |
|  3   |          C         |
x------x--------------------x

ตารางรายละเอียด

x------x--------------------x-------x
| Id   |      PERIOD        |   QTY |
x------x--------------------x-------x
|  1   |   2014-01-13       |   10  |
|  1   |   2014-01-11       |   15  |
|  1   |   2014-01-12       |   20  |
|  2   |   2014-01-06       |   30  |
|  2   |   2014-01-08       |   40  |
x------x--------------------x-------x

มีหลาย ๆ สถานการณ์ที่เราจำเป็นต้องเปลี่ยนเป็นด้วยINNER JOINCROSS APPLY

1. เข้าร่วมสองตารางตามTOP nผลลัพธ์

พิจารณาถ้าเราต้องเลือกIdและNameจากMasterและวันที่สองวันที่ผ่านมาสำหรับแต่ละจากIdDetails table

SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
INNER JOIN
(
    SELECT TOP 2 ID, PERIOD,QTY 
    FROM DETAILS D      
    ORDER BY CAST(PERIOD AS DATE)DESC
)D
ON M.ID=D.ID

แบบสอบถามด้านบนสร้างผลลัพธ์ต่อไปนี้

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-12   |  20   |
x------x---------x--------------x-------x

ดูว่ามันสร้างผลลัพธ์สำหรับสองวันที่ผ่านมาด้วยสองวันที่Idแล้วจากนั้นก็เข้าร่วมบันทึกเหล่านี้เฉพาะในแบบสอบถามด้านนอกIdซึ่งผิด สิ่งนี้ควรส่งคืนทั้งIds1 และ 2 แต่จะคืนค่าเพียง 1 เนื่องจาก 1 มีสองวันที่ผ่านมา CROSS APPLYเพื่อให้บรรลุนี้เราจำเป็นต้องใช้

SELECT M.ID,M.NAME,D.PERIOD,D.QTY
FROM MASTER M
CROSS APPLY
(
    SELECT TOP 2 ID, PERIOD,QTY 
    FROM DETAILS D  
    WHERE M.ID=D.ID
    ORDER BY CAST(PERIOD AS DATE)DESC
)D

และรูปแบบผลลัพธ์ต่อไปนี้

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-12   |  20   |
|   2  |   B     | 2014-01-08   |  40   |
|   2  |   B     | 2014-01-06   |  30   |
x------x---------x--------------x-------x

นี่คือวิธีการทำงาน แบบสอบถามภายในCROSS APPLYสามารถอ้างอิงตารางด้านนอกซึ่งINNER JOINไม่สามารถทำได้ (จะเกิดข้อผิดพลาดในการคอมไพล์) เมื่อค้นหาสองวันที่ผ่านมาการเข้าร่วมจะเกิดขึ้นภายในCROSS APPLYเช่นWHERE M.ID=D.ID.

2. เมื่อเราต้องการINNER JOINฟังก์ชั่นการใช้ฟังก์ชั่น

CROSS APPLYสามารถนำมาใช้แทนด้วยINNER JOINเมื่อเราต้องการที่จะได้รับผลจากตารางและMasterfunction

SELECT M.ID,M.NAME,C.PERIOD,C.QTY
FROM MASTER M
CROSS APPLY dbo.FnGetQty(M.ID) C

และนี่คือฟังก์ชั่น

CREATE FUNCTION FnGetQty 
(   
    @Id INT 
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT ID,PERIOD,QTY 
    FROM DETAILS
    WHERE ID=@Id
)

ซึ่งสร้างผลลัพธ์ต่อไปนี้

x------x---------x--------------x-------x
|  Id  |   Name  |   PERIOD     |  QTY  |
x------x---------x--------------x-------x
|   1  |   A     | 2014-01-13   |  10   |
|   1  |   A     | 2014-01-11   |  15   |
|   1  |   A     | 2014-01-12   |  20   |
|   2  |   B     | 2014-01-06   |  30   |
|   2  |   B     | 2014-01-08   |  40   |
x------x---------x--------------x-------x

ข้อดีเพิ่มเติมของ CROSS ใช้

APPLYUNPIVOTสามารถนำมาใช้แทนสำหรับ อย่างใดอย่างหนึ่งCROSS APPLYหรือOUTER APPLYสามารถนำมาใช้ที่นี่ซึ่งสามารถใช้แทนกัน

พิจารณาว่าคุณมีตารางด้านล่าง (ชื่อMYTABLE)

x------x-------------x--------------x
|  Id  |   FROMDATE  |   TODATE     |
x------x-------------x--------------x
|   1  |  2014-01-11 | 2014-01-13   | 
|   1  |  2014-02-23 | 2014-02-27   | 
|   2  |  2014-05-06 | 2014-05-30   | 
|   3  |     NULL    |    NULL      |
x------x-------------x--------------x

แบบสอบถามอยู่ด้านล่าง

SELECT DISTINCT ID,DATES
FROM MYTABLE 
CROSS APPLY(VALUES (FROMDATE),(TODATE))
COLUMNNAMES(DATES)

ซึ่งทำให้คุณได้ผลลัพธ์

  x------x-------------x
  | Id   |    DATES    |
  x------x-------------x
  |  1   |  2014-01-11 |
  |  1   |  2014-01-13 |
  |  1   |  2014-02-23 |
  |  1   |  2014-02-27 |
  |  2   |  2014-05-06 |
  |  2   |  2014-05-30 | 
  |  3   |    NULL     | 
  x------x-------------x

4
ตัวอย่างที่ยอดเยี่ยมกับระเบียน 2 vs 4 และช่วยให้ฉันเข้าใจบริบทที่ต้องการสิ่งนี้
trnelson

13
คำตอบนี้พิสูจน์ว่ามันคุ้มค่าที่จะเลื่อนหน้าลงแทนที่จะเลือกที่จะยอมรับ
Mostafa Armandi

2
ตัวอย่างที่ดีที่สุดจนถึงตอนนี้เพื่ออธิบายการใช้ APPLY ... ฉันได้อ่านบทความจำนวนมากและตระหนักว่าคำอธิบายนี้ล้างรูปภาพเหมือนน้ำ ขอบคุณมากครับ
AG7

1
สำหรับจุดที่ 1 ซึ่งเรามี 2 แถวสำหรับ ID 1 แทนที่จะเป็น 4 แถวสำหรับ ID 1, 2 เราจะไม่ใช้การรวมซ้ายแทน
โจเซฟโช

43

สำหรับฉันแล้วดูเหมือนว่า CROSS สามารถใช้งานช่องว่างบางอย่างได้เมื่อทำงานกับเขตข้อมูลจากการคำนวณในแบบสอบถามแบบซับซ้อน / ซ้อนและทำให้พวกเขาง่ายและอ่านได้มากขึ้น

ตัวอย่างง่าย ๆ : คุณมี DoB และคุณต้องการนำเสนอเขตข้อมูลที่เกี่ยวข้องกับอายุที่หลากหลายซึ่งจะต้องพึ่งพาแหล่งข้อมูลอื่น ๆ (เช่นการจ้างงาน) เช่นอายุกลุ่มอายุกลุ่มอายุ AgeAtHiring, MinimumRetirementDate เป็นต้นเพื่อใช้ในแอปพลิเคชันผู้ใช้ปลายทาง (Excel PivotTables เป็นต้น)

ตัวเลือกมี จำกัด และไม่ค่อยสง่างาม:

  • ข้อความค้นหาย่อย JOIN ไม่สามารถแนะนำค่าใหม่ในชุดข้อมูลโดยยึดตามข้อมูลในแบบสอบถามหลัก (จะต้องยืนอยู่บนตัวของมันเอง)

  • UDF นั้นเรียบร้อย แต่ช้าเพราะมีแนวโน้มที่จะป้องกันการทำงานแบบขนาน และการเป็นนิติบุคคลแยกต่างหากอาจเป็นสิ่งที่ดี (รหัสน้อยกว่า) หรือสิ่งที่ไม่ดี (รหัสนั้นอยู่ที่ไหน)

  • ตารางแยก บางครั้งพวกเขาสามารถทำงานได้ แต่เร็ว ๆ นี้คุณจะเข้าร่วมกับคิวรีย่อยกับ UNIONs มากมาย ระเบียบใหญ่

  • สร้างมุมมองแบบจุดประสงค์เดียวอีกมุมหนึ่งโดยสมมติว่าการคำนวณของคุณไม่ต้องการข้อมูลที่ได้จากการสอบถามหลัก

  • ตารางที่เป็นสื่อกลาง ใช่ ... ซึ่งมักจะใช้งานได้และมักจะเป็นตัวเลือกที่ดีเนื่องจากสามารถจัดทำดัชนีและรวดเร็ว แต่ประสิทธิภาพยังลดลงเนื่องจากคำสั่ง UPDATE ไม่ขนานและไม่อนุญาตให้เรียงซ้อนสูตร (ใช้ผลลัพธ์ซ้ำ) เพื่ออัปเดตหลายฟิลด์ภายใน คำสั่งเดียวกัน และบางครั้งคุณต้องการทำสิ่งต่าง ๆ ในคราวเดียว

  • การทำแบบสอบถาม ได้ทุกเวลาคุณสามารถใส่วงเล็บลงในแบบสอบถามทั้งหมดและใช้เป็นแบบสอบถามย่อยที่คุณสามารถจัดการข้อมูลต้นฉบับและเขตข้อมูลจากการคำนวณได้ แต่คุณสามารถทำสิ่งนี้ได้มากก่อนที่มันจะน่าเกลียด น่าเกลียดมาก.

  • รหัสซ้ำ อะไรคือค่าที่ยิ่งใหญ่ที่สุดของแถลงการณ์ยาวที่สุด (CASE ... ELSE ... END) นั่นจะอ่านได้!

    • บอกลูกค้าของคุณให้คำนวณสิ่งที่น่ารังเกียจด้วยตัวเอง

ฉันพลาดอะไรไปหรือเปล่า? อาจรู้สึกดังนั้นเพื่อแสดงความคิดเห็น แต่เฮ้ CROSS ใช้เป็นเหมือนสวรรค์ในสถานการณ์เช่นนี้: คุณเพียงแค่เพิ่มความเรียบง่ายCROSS APPLY (select tbl.value + 1 as someFormula) as crossTblและvoilà! ขณะนี้เขตข้อมูลใหม่ของคุณพร้อมสำหรับการใช้งานจริงเหมือนอยู่ในแหล่งข้อมูลของคุณเสมอ

ค่าที่แนะนำผ่าน CROSS APPLY สามารถ ...

  • ใช้เพื่อสร้างเขตข้อมูลจากการคำนวณหนึ่งหรือหลายเขตโดยไม่ต้องเพิ่มปัญหาความซับซ้อนหรือความสามารถในการอ่านในการผสม
  • เช่นเดียวกับ JOIN ข้อความสั่ง CROSS APPLY หลายรายการสามารถอ้างถึงตัวเองได้: CROSS APPLY (select crossTbl.someFormula + 1 as someMoreFormula) as crossTbl2
  • คุณสามารถใช้ค่าที่ CROSS นำมาใช้ในเงื่อนไขการเข้าร่วมที่ตามมา
  • เป็นโบนัสมีฟังก์ชั่นที่มีค่าตาราง

แดงไม่มีอะไรที่พวกเขาทำไม่ได้!


1
นี่เป็น +1 ที่ยอดเยี่ยมจากฉันเพราะฉันประหลาดใจที่ไม่ได้พูดถึงบ่อยขึ้น บางทีคุณอาจขยายตัวอย่างนี้เพื่อแสดงวิธีที่คุณสามารถทำการคำนวณ "ขั้นตอน" ในห่วงโซ่ของค่าที่ได้มา? เช่น CROSS นำไปใช้ (เลือก crossTbl.value * tbl.multiplier เป็นทวีคูณ) multiTbl - CROSS ใช้ (เลือก multiTbl.Multiplied / tbl.DerivativeRatio มาแล้ว) ได้รับ tbl - etc ...
mrmillsy

1
มีข้อมูล / ตัวอย่างเพิ่มเติมเกี่ยวกับวิธีการใช้ Cross Apply แทน CASE ..ELSE..END ไหม?
przemo_li

3
@przemo_li สามารถใช้เพื่อเก็บผลลัพธ์ของคำสั่ง case (เหนือสิ่งอื่นใด) เพื่ออ้างอิง โครงสร้างอาจเป็นดังนี้: SELECT CASE เมื่อ subquery.intermediateResult> 0 จากนั้น "ใช่" ELSE "ไม่ใช่" สิ้นสุดจากนอกตารางที่ใช้งานได้ (เลือก CASE ... END ... ELSE เป็น middleResult) เป็นแบบสอบถามย่อย
mtone

14

Cross ใช้งานได้ดีกับเขตข้อมูล XML เช่นกัน หากคุณต้องการเลือกค่าโหนดร่วมกับสาขาอื่น

ตัวอย่างเช่นหากคุณมีตารางที่มี xml อยู่

<root>
    <subnode1>
       <some_node value="1" />
       <some_node value="2" />
       <some_node value="3" />
       <some_node value="4" />
    </subnode1>
</root>

การใช้แบบสอบถาม

SELECT
       id as [xt_id]
      ,xmlfield.value('(/root/@attribute)[1]', 'varchar(50)') root_attribute_value
  ,node_attribute_value = [some_node].value('@value', 'int')
  ,lt.lt_name   
FROM dbo.table_with_xml xt
CROSS APPLY xmlfield.nodes('/root/subnode1/some_node') as g ([some_node])
LEFT OUTER JOIN dbo.lookup_table lt
ON [some_node].value('@value', 'int') = lt.lt_id

จะส่งคืนผลลัพธ์

xt_id root_attribute_value node_attribute_value lt_name
----------------------------------------------------------------------
1     test1            1                    Benefits
1     test1            4                    FINRPTCOMPANY

13

คำตอบนี้ได้รับการตอบรับอย่างดีทางเทคนิค แต่ขอยกตัวอย่างที่เป็นรูปธรรมว่ามันมีประโยชน์มากเพียงใด:

ให้บอกว่าคุณมีสองตารางลูกค้าและคำสั่งซื้อ ลูกค้ามีคำสั่งซื้อมากมาย

ฉันต้องการสร้างมุมมองที่ให้รายละเอียดเกี่ยวกับลูกค้าและคำสั่งซื้อล่าสุดที่พวกเขาทำ ด้วยการเข้าร่วมเพียงอย่างเดียวสิ่งนี้จะต้องมีการรวมตัวเองและการรวมตัวซึ่งไม่สวย แต่ด้วย Cross Apply มันง่ายมาก:

SELECT *
FROM Customer
CROSS APPLY (
  SELECT TOP 1 *
  FROM Order
  WHERE Order.CustomerId = Customer.CustomerId
  ORDER BY OrderDate DESC
) T

7

การใช้ข้ามสามารถใช้เพื่อแทนที่เคียวรี่ย่อยที่คุณต้องการคอลัมน์ของเคียวรีย่อย

แบบสอบถามย่อย

select * from person p where
p.companyId in(select c.companyId from company c where c.companyname like '%yyy%')

ที่นี่ฉันจะไม่สามารถเลือกคอลัมน์ของตาราง บริษัท ได้ดังนั้นการใช้ cross ใช้

select P.*,T.CompanyName
from Person p
cross apply (
    select *
    from Company C
    where p.companyid = c.companyId and c.CompanyName like '%yyy%'
) T

5

ฉันเดาว่ามันควรจะอ่านได้)

CROSS ใช้เฉพาะกับคนที่อ่านเพื่อบอกพวกเขาว่ามีการใช้ UDF ซึ่งจะนำไปใช้กับแต่ละแถวจากตารางด้านซ้าย

แน่นอนว่ามีข้อ จำกัด อื่น ๆ ที่ใช้ CROSS ใช้ดีกว่าเข้าร่วมที่เพื่อนคนอื่น ๆ ได้โพสต์ข้างต้น


4

นี่คือบทความที่อธิบายทุกอย่างโดยมีความแตกต่างด้านประสิทธิภาพและการใช้งานมากกว่า JOINS

SQL Server CROSS ใช้และนอกใช้ผ่าน JOINS

ตามที่แนะนำในบทความนี้ไม่มีความแตกต่างระหว่างประสิทธิภาพสำหรับการดำเนินการเข้าร่วมปกติ (INNER และ CROSS)

ป้อนคำอธิบายรูปภาพที่นี่

ความแตกต่างของการใช้งานมาถึงเมื่อคุณต้องทำแบบสอบถามเช่นนี้:

CREATE FUNCTION dbo.fn_GetAllEmployeeOfADepartment(@DeptID AS INT)  
RETURNS TABLE 
AS 
RETURN 
   ( 
   SELECT * FROM Employee E 
   WHERE E.DepartmentID = @DeptID 
   ) 
GO 
SELECT * FROM Department D 
CROSS APPLY dbo.fn_GetAllEmployeeOfADepartment(D.DepartmentID)

นั่นคือเมื่อคุณต้องเกี่ยวข้องกับฟังก์ชั่น สิ่งนี้ไม่สามารถทำได้โดยใช้ INNER JOIN ซึ่งจะทำให้คุณเกิดข้อผิดพลาด"ตัวระบุหลายส่วน" D.DepartmentID "ไม่สามารถผูกได้" ที่นี่ค่าจะถูกส่งผ่านไปยังฟังก์ชั่นในขณะที่อ่านแต่ละแถว ฟังดูเท่มาก :)


3

ฉันไม่แน่ใจว่าสิ่งนี้มีคุณสมบัติเป็นเหตุผลที่จะใช้ Cross Applys กับ Inner Join หรือไม่ แต่แบบสอบถามนี้ได้รับคำตอบสำหรับฉันในฟอรั่มโพสต์โดยใช้ Cross Apply ดังนั้นฉันไม่แน่ใจว่ามีวิธีที่เท่าเทียมกันโดยใช้ Inner Join หรือไม่

Create PROCEDURE [dbo].[Message_FindHighestMatches]

-- Declare the Topical Neighborhood
@TopicalNeighborhood nchar(255)

เริ่มต้น

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

Create table  #temp
(
    MessageID         int,
    Subjects          nchar(255),
    SubjectsCount    int
)

Insert into #temp Select MessageID, Subjects, SubjectsCount From Message

Select Top 20 MessageID, Subjects, SubjectsCount,
    (t.cnt * 100)/t3.inputvalues as MatchPercentage

From #temp 

cross apply (select count(*) as cnt from dbo.Split(Subjects,',') as t1
             join dbo.Split(@TopicalNeighborhood,',') as t2
             on t1.value = t2.value) as t
cross apply (select count(*) as inputValues from dbo.Split(@TopicalNeighborhood,',')) as t3

Order By MatchPercentage desc

drop table #temp

END


3

สาระสำคัญของตัวดำเนินการ APPLY คือการอนุญาตให้มีความสัมพันธ์ระหว่างด้านซ้ายและด้านขวาของตัวดำเนินการในส่วนคำสั่ง FROM

ตรงกันข้ามกับ JOIN ความสัมพันธ์ระหว่างอินพุตไม่ได้รับอนุญาต

เมื่อพูดถึงสหสัมพันธ์ในตัวดำเนินการประยุกต์ฉันหมายถึงทางด้านขวาที่เราสามารถใส่:

  • ตารางที่ได้รับ - เป็นแบบสอบถามย่อยที่มีความสัมพันธ์กับนามแฝง
  • ฟังก์ชั่นการประเมินค่าตาราง - มุมมองแนวคิดพร้อมพารามิเตอร์ซึ่งพารามิเตอร์สามารถอ้างถึงทางด้านซ้าย

ทั้งสองสามารถส่งคืนหลายคอลัมน์และแถว


2

นี่อาจเป็นคำถามเก่า แต่ฉันก็ยังรักพลังของ CROSS ที่ใช้เพื่อทำให้การใช้ตรรกะง่ายขึ้นอีกครั้งและเพื่อให้กลไก "การผูกมัด" สำหรับผลลัพธ์

ฉันได้ให้ SQL Fiddle ด้านล่างซึ่งแสดงตัวอย่างง่ายๆว่าคุณสามารถใช้ CROSS APPLY เพื่อดำเนินการทางตรรกะที่ซับซ้อนกับชุดข้อมูลของคุณได้อย่างไรโดยไม่เกิดความยุ่งเหยิง ไม่ยากที่จะคาดการณ์จากที่นี่การคำนวณที่ซับซ้อนมากขึ้น

http://sqlfiddle.com/#!3/23862/2


1

ในขณะที่การสืบค้นส่วนใหญ่ที่ใช้ CROSS APPLY สามารถเขียนใหม่ได้โดยใช้ INNER JOIN แต่ CROSS APPLY สามารถสร้างแผนการดำเนินการที่ดีกว่าและประสิทธิภาพที่ดีขึ้นเนื่องจากสามารถ จำกัด ชุดที่จะเข้าร่วมก่อนที่การเข้าร่วมจะเกิดขึ้น

ขโมยมาจากที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.