เลือกเข้าสู่ตัวแปรตารางใน T-SQL


372

มีคิวรี SELECT ที่ซับซ้อนซึ่งฉันต้องการแทรกแถวทั้งหมดลงในตัวแปรตาราง แต่ T-SQL ไม่อนุญาต

ในบรรทัดเดียวกันคุณไม่สามารถใช้ตัวแปรตารางที่มีคำสั่ง SELECT INTO หรือ INSERT EXEC http://odetocode.com/Articles/365.aspx

ตัวอย่างสั้น ๆ :

declare @userData TABLE(
                        name varchar(30) NOT NULL,
                        oldlocation varchar(30) NOT NULL
                       )

SELECT name, location
INTO @userData
FROM myTable
    INNER JOIN otherTable ON ...
WHERE age > 30

ข้อมูลในตัวแปรตารางจะถูกนำมาใช้ในภายหลังเพื่อแทรก / อัปเดตกลับเข้าไปในตารางที่แตกต่างกัน เป้าหมายของการทำเช่นนี้คือการทำให้สคริปต์อ่านง่ายขึ้นและสามารถปรับแต่งได้ง่ายกว่าทำSELECT INTOในตารางที่ถูกต้องโดยตรง ประสิทธิภาพไม่ใช่ปัญหาเนื่องจากrowcountมีขนาดค่อนข้างเล็กและทำงานด้วยตนเองเมื่อจำเป็นเท่านั้น
... หรือแค่บอกฉันว่าฉันทำผิดทั้งหมดหรือเปล่า

คำตอบ:


601

ลองสิ่งนี้:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData (name, oldlocation)
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

2
หากคุณ "เลือกชื่อตำแหน่งจาก myTable" เป็นค่าที่คุณจะแทรกลงในตาราง UserData ไม่สำคัญว่าชื่อของตัวแปรในตัวเลือกจะตรงกับชื่อในนิยามของตารางหรือไม่ คุณกำลังเลือก 'ชื่อ' เพื่อไปที่ตัวแปร 'ชื่อ' UserData แต่คุณกำลังเลือก 'ตำแหน่งที่ตั้ง' และกำหนดให้กับตัวแปร 'Oldlocation' ของ UserData SQL จะจับคู่สิ่งเหล่านี้โดยอัตโนมัติหรือจะยกเว้นอะไรบางอย่าง?
Aran Mulholland

ไม่สำคัญว่าจะมีเพียงชื่อประเภทเท่านั้น
CristiC

5
ว้าวชนิดของการทำให้ความรู้สึก แต่ในเวลาเดียวกัน parser ในตัวผมรู้สึกโกรธเคืองชนิดของ :)
อรัญมัลฮอลแลนด์

ดูเหมือนว่าฉันจะไม่สามารถใช้สิ่งนี้ในคำสั่ง UPDATE: gist link
Paul-Sebastian Manole

1
ในคำสั่งแทรกหากคุณไม่ประกาศคอลัมน์อย่างชัดเจนคอลัมน์เหล่านั้นจะถูกแมปตามลำดับที่ประกาศในคำสั่งสร้างตารางดั้งเดิมเช่นเดียวกับ select * ดังนั้นตำแหน่งในคำสั่ง select จะถูกแมปกับ Oldlocation ในตาราง @userData เนื่องจากตำแหน่งอยู่ในตำแหน่ง 2 ในชุดผลลัพธ์ของการเลือกและ Oldlocation เป็นคอลัมน์ 2 ในนิยามตาราง ที่กล่าวว่าไม่เคยทำเช่นนี้ ไม่ควรพึ่งพาการเรียงลำดับฐานข้อมูลของคอลัมน์หรือแถว ชัดเจนเกี่ยวกับเรื่องนี้เสมอ
absmiths

94

วัตถุประสงค์ของSELECT INTOคือ (ต่อเอกสารเน้นของฉัน)

เพื่อสร้างตารางใหม่จากค่าในตารางอื่น

แต่คุณมีตารางเป้าหมายอยู่แล้ว! ดังนั้นสิ่งที่คุณต้องการคือ

INSERTงบเพิ่มหนึ่งหรือมากกว่าหนึ่งแถวใหม่ในตาราง

คุณสามารถระบุค่าข้อมูลด้วยวิธีต่อไปนี้:

...

โดยใช้SELECTแบบสอบถามย่อยเพื่อระบุค่าข้อมูลสำหรับหนึ่งหรือหลายแถวเช่น:

  INSERT INTO MyTable 
 (PriKey, Description)
        SELECT ForeignKey, Description
        FROM SomeView

และในรูปแบบนี้มันได้รับอนุญาตMyTableให้เป็นตัวแปรตาราง


1
หวังว่าคำตอบที่ได้รับการยอมรับจะรวมข้อมูลนี้!
Davie Brown

ฉันได้รับ MyTable คือ "ชื่อวัตถุที่ไม่ถูกต้อง" ในการทำเช่นนี้
Mike Flynn

@MikeFlynn MyTableที่นี่เป็นตัวยึดสำหรับชื่อของคุณที่เกิดขึ้นจริงตาราง ผมไม่คิดว่ามีฐานข้อมูลจริงใด ๆ กับตารางชื่อMyTable...
AakashM

และถ้าฉันต้องการสร้าง / ประกาศตัวแปรตารางด้วย SELECT INTO ... ? ตัวอย่างเช่นเมื่อต้องการกำหนดคอลัมน์ของตัวแปรตารางเป็น t1.somecolumn, t1.othercolumn, t2. *
Armando

27

คุณยังสามารถใช้นิพจน์ทั่วไปเพื่อจัดเก็บชุดข้อมูลชั่วคราว พวกเขามีความสง่างามและเป็นมิตรมากขึ้น:

WITH userData (name, oldlocation)
AS
(
  SELECT name, location 
  FROM   myTable    INNER JOIN 
         otherTable ON ...
  WHERE  age>30
)
SELECT * 
FROM   userData -- you can also reuse the recordset in subqueries and joins

รักสิ่งนี้! ขอบคุณ.
fourpastmidnight

ฉันไม่คิดว่าสิ่งนี้จะทำสำเนาหากคุณลบหรืออัปเดตจาก userData มันจะไม่ลบและอัปเดตระเบียนในตารางดั้งเดิมของคุณหรือไม่
atreeon

ใช่ DELETE และ UPDATE บน CTE จะแก้ไขตารางต้นฉบับตราบใดที่ CTE ไม่ได้อ้างอิงหลายตารางโดยใช้การรวมสหภาพแรงงาน ฯลฯ
nanestev

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

16

คุณสามารถลองใช้ตารางชั่วคราว ... หากคุณไม่ได้ทำจากแอปพลิเคชัน (มันอาจจะโอเคที่จะเรียกใช้ด้วยตนเอง)

SELECT name, location INTO #userData FROM myTable
INNER JOIN otherTable ON ...
WHERE age>30

คุณข้ามความพยายามในการประกาศตารางด้วยวิธีนี้ ... ช่วยสำหรับคิวรี adhoc ... นี่เป็นการสร้างตาราง temp เฉพาะที่ซึ่งจะไม่ปรากฏในเซสชันอื่นจนกว่าคุณจะอยู่ในเซสชันเดียวกัน อาจมีปัญหาหากคุณเรียกใช้คิวรีจากแอป

หากคุณต้องการให้มันรันบนแอปให้ใช้ตัวแปรที่ประกาศด้วยวิธีนี้:

DECLARE @userData TABLE(
    name varchar(30) NOT NULL,
    oldlocation varchar(30) NOT NULL
);

INSERT INTO @userData
SELECT name, location FROM myTable
INNER JOIN otherTable ON ...
WHERE age > 30;

แก้ไข: คุณหลายคนพูดถึงการเปิดเผยการปรับปรุงเซสชันจากการเชื่อมต่อ การสร้างตาราง temp ไม่ใช่ตัวเลือกสำหรับเว็บแอปพลิเคชันเนื่องจากสามารถนำเซสชันมาใช้ใหม่ได้ให้ใช้ตัวแปร temp ในกรณีเหล่านั้น


2
ขออภัยลืมพูดถึงฉันไม่มีสิทธิ์ในการสร้างตาราง
Indrek

6
การสร้างอุณหภูมิมีค่าใช้จ่ายมากกว่าเล็กน้อย
paparazzo

2
การใช้ตาราง temp ไม่ปลอดภัยเสมอไป ตัวอย่างเช่นบริการเว็บ ด้วย webservices ที่มีการเชื่อมต่อเดียวเพื่อ จำกัด การเชื่อมต่อสูงสุดบนเซิร์ฟเวอร์และปกป้อง SQL อีกเล็กน้อยตาราง temp จะมีอยู่สำหรับทุกแบบสอบถามผ่านและสามารถเขียนทับใครบางคนที่กำลังใช้อยู่
Franck

12
@Franck - หากคุณใช้ตารางชั่วคราวทั่วโลก (สองคำนำหน้าแฮช) คุณถูกต้อง อย่างไรก็ตามตาราง temp ท้องถิ่น (คำนำหน้าแฮชหนึ่งคำ) จะถูกแยกออกเป็นเซสชันเดียว (หรือการเชื่อมต่อเดี่ยว) ดังนั้นจะไม่มีปัญหาเกิดขึ้นพร้อมกันที่คุณพูดถึงนอกจากคุณจะใช้การเชื่อมต่อเดียวสำหรับคำขอทั้งหมด (ไม่ใช่ ให้คำแนะนำ) ความหมายของประสิทธิภาพที่เป็นไปได้ยังคงอยู่
maf748

@GazB แน่นอนว่าคำสั่งใด ๆ functionที่มีผลข้างเคียงได้รับการยกเว้นจากการถูกนำมาใช้ใน จากประสบการณ์ของผมในกรณีส่วนใหญ่ที่มีคนคิดว่าพวกเขาจำเป็นต้องใช้งบดังกล่าวนี้จริงหมายความว่าพวกเขาควรจะคิดใหม่ของพวกเขาfunction- หรืออย่างน้อย refactor procedureไป พูดให้ตัวเองอย่างน้อย :-)
underscore_d


5

สร้างตารางชั่วคราวก่อน:

ขั้นตอนที่ 1:

create table #tblOm_Temp (

    Name varchar(100),
    Age Int ,
    RollNumber bigint
)

** ขั้นตอนที่ 2: ** แทรกค่าบางอย่างในตารางชั่วคราว

insert into #tblom_temp values('Om Pandey',102,1347)

ขั้นตอนที่ 3:ประกาศตาราง Variable เพื่อเก็บข้อมูลตาราง temp

declare   @tblOm_Variable table(

    Name Varchar(100),
    Age int,
    RollNumber bigint
)

ขั้นตอนที่ 4:เลือกค่าจากตารางอุณหภูมิและแทรกลงในตัวแปรตาราง

insert into @tblOm_Variable select * from #tblom_temp

ค่าสุดท้ายจะถูกแทรกจากตาราง temp ไปยังตัวแปร Table

ขั้นตอนที่ 5:สามารถตรวจสอบค่าที่แทรกในตัวแปรตาราง

select * from @tblOm_Variable

1

ตกลงตอนนี้ด้วยความพยายามมากพอฉันสามารถแทรก @table โดยใช้ด้านล่าง:

INSERT @TempWithheldTable SELECT
a.SuspendedReason, a.SuspendedNotes, a.SuspendedBy, a.ReasonCode จาก OPENROWSET (กลุ่ม 'C: \ DataBases \ WithHeld.csv', FORMATFILE = N'C: \ DataB \ Format.txt ',
ERROR N'C: \ Temp \ MovieLensRatings.txt ') เป็น;

สิ่งสำคัญที่นี่คือการเลือกคอลัมน์ที่จะแทรก


ฉันได้รับ 'ต้องประกาศตัวแปรตาราง "@TempWithheldTable" ข้อผิดพลาดการคอมไพล์
atreeon

-5

เหตุผลหนึ่งที่ใช้ SELECT INTO คือช่วยให้คุณสามารถใช้ตัวตนได้:

SELECT IDENTITY(INT,1,1) AS Id, name
INTO #MyTable 
FROM (SELECT name FROM AnotherTable) AS t

สิ่งนี้จะไม่ทำงานกับตัวแปรตารางซึ่งแย่มาก ...


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