PILIH KE variabel tabel dalam T-SQL

372

Punya query SELECT yang kompleks, dari mana saya ingin memasukkan semua baris ke dalam variabel tabel, tetapi T-SQL tidak mengizinkannya.

Sepanjang baris yang sama, Anda tidak bisa menggunakan variabel tabel dengan kueri SELECT INTO atau INSERT EXEC. http://odetocode.com/Articles/365.aspx

Contoh singkat:

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

Data dalam variabel tabel nantinya akan digunakan untuk menyisipkan / memperbarui kembali ke tabel yang berbeda (kebanyakan salinan data yang sama dengan pembaruan kecil). Tujuannya adalah membuat skrip sedikit lebih mudah dibaca dan lebih mudah disesuaikan daripada melakukan SELECT INTOlangsung ke tabel yang benar. Performa bukan masalah, karena rowcountini cukup kecil dan hanya berjalan secara manual bila diperlukan.
... atau katakan saja jika saya melakukan semuanya salah.

Indrek
sumber

Jawaban:

601

Coba sesuatu seperti ini:

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;
CristiC
sumber
2
Jika Anda "SELECT name, location FROM myTable" sebagai nilai yang akan Anda sisipkan ke tabel UserData tidak masalah jika nama-nama variabel dalam pilih cocok dengan nama-nama dalam definisi tabel. Anda memilih 'nama' untuk masuk ke variabel 'nama' UserData tetapi Anda memilih 'lokasi' dan entah bagaimana menugaskannya ke variabel 'lokasi lama' UserData. Apakah SQL hanya memetakan ini secara otomatis atau akankah ia membuat semacam pengecualian?
Aran Mulholland
Tidak masalah namanya, hanya tipe kolomnya.
CristiC
5
Wow hal semacam itu masuk akal tetapi pada saat yang sama pengurai dalam diriku merasa agak tersinggung :)
Aran Mulholland
Sepertinya saya tidak dapat menggunakan ini dalam pernyataan UPDATE: tautan utama
Paul-Sebastian Manole
1
Dalam pernyataan penyisipan, jika Anda tidak mendeklarasikan kolom secara eksplisit, maka mereka dipetakan dalam urutan yang dinyatakan dalam pernyataan tabel buat asli, seperti halnya pilih * lakukan. Jadi, lokasi dalam pernyataan pilih dipetakan ke oldlocation di tabel @userData karena lokasi berada di posisi 2 di set hasil pilih, dan oldlocation adalah kolom 2 dalam definisi tabel. Yang mengatakan, jangan pernah melakukan ini. Urutan basis data kolom atau baris tidak bisa diandalkan. Selalu jelas tentang hal ini.
absmiths
94

Tujuannya SELECT INTOadalah (sesuai dokumen, penekanan saya)

Untuk membuat tabel baru dari nilai di tabel lain

Tetapi Anda sudah memiliki tabel target! Jadi yang Anda inginkan adalah

The INSERTpernyataan menambahkan satu atau lebih baris baru ke tabel

Anda dapat menentukan nilai data dengan cara berikut:

...

Dengan menggunakan SELECTsubquery untuk menentukan nilai data untuk satu atau lebih baris, seperti:

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

Dan dalam sintaks ini , itu diizinkan untuk MyTablemenjadi variabel tabel.

AakashM
sumber
1
Sangat berharap jawaban yang diterima termasuk info ini!
Davie Brown
Saya mendapatkan MyTable adalah "Nama Objek Tidak Valid" melakukan ini, jadi ada sesuatu yang hilang dari jawaban ini.
Mike Flynn
@ MikeFlynn di MyTablesini adalah penampung untuk nama tabel Anda yang sebenarnya . Saya tidak berpikir ada database nyata dengan tabel bernama ...MyTable
AakashM
Dan jika saya ingin membuat / mendeklarasikan variabel tabel dengan SELECT INTO ...? Misalnya, untuk mendefinisikan kolom variabel tabel sebagai t1.somecolumn, t1.othercolumn, t2. *
Armando
27

Anda juga bisa menggunakan ekspresi tabel umum untuk menyimpan kumpulan data sementara. Mereka lebih elegan dan ramah adhoc:

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
nanestev
sumber
Suka ini! Terima kasih.
fourpastmidnight
Saya tidak berpikir ini membuat salinan, jika Anda menghapus atau memperbarui dari userData apakah itu tidak akan menghapus dan memperbarui catatan dalam tabel asli Anda?
atreeon
Ya, HAPUS dan PEMBARUAN pada CTE akan memodifikasi tabel sumber selama CTE tidak mereferensikan beberapa tabel menggunakan gabungan, serikat pekerja, dll.
nanestev
2
Kelemahan dari ini adalah bahwa Anda hanya dapat menggunakan tabel CTE di perintah segera berikut. Jika Anda perlu membuat lebih dari satu melewati hasil yang ditetapkan untuk alasan apa pun CTE tidak akan berfungsi. OP tampaknya menyiratkan bahwa beberapa modifikasi akan dibuat, dalam hal ini ini tidak akan berfungsi - "Data dalam variabel tabel nantinya akan digunakan untuk memasukkan / memperbaruinya kembali ke tabel yang berbeda (kebanyakan salinan data yang sama dengan minor pembaruan). "
Tony
16

Anda dapat mencoba menggunakan tabel sementara ... jika Anda tidak melakukannya dari aplikasi. (Mungkin ok untuk menjalankan ini secara manual)

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

Anda melewatkan upaya untuk mendeklarasikan tabel seperti itu ... Membantu permintaan adhoc ... Ini membuat tabel temp lokal yang tidak akan terlihat oleh sesi lain kecuali Anda berada di sesi yang sama. Mungkin masalah jika Anda menjalankan kueri dari suatu aplikasi.

jika Anda mengharuskannya berjalan di aplikasi, gunakan variabel yang dideklarasikan dengan cara ini:

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;

Sunting: karena banyak dari Anda menyebutkan visibilitas yang diperbarui ke sesi dari koneksi. Membuat tabel temp bukan pilihan untuk aplikasi web, karena sesi dapat digunakan kembali, menempel variabel tempa dalam kasus tersebut

Mulki
sumber
2
Maaf, lupa menyebutkan bahwa saya tidak memiliki hak untuk CREATE TABLE.
Indrek
6
Menciptakan temp memiliki overhead yang lebih sedikit.
paparazzo
2
menggunakan tabel temp tidak selalu aman. Misalnya, layanan web. Dengan layanan web dengan satu koneksi untuk membatasi koneksi maksimal pada server DAN sedikit melindungi SQL, tabel temp akan ada untuk SETIAP kueri yang melewati dan dapat menimpa seseorang yang saat ini menggunakannya.
Franck
12
@ Franck - jika Anda menggunakan tabel temp global (dua awalan hash) Anda benar. Namun, tabel temp lokal (awalan satu hash) akan diisolasi untuk satu sesi (alias koneksi tunggal) sehingga tidak akan ada masalah konkurensi yang Anda singgung kecuali Anda menggunakan koneksi tunggal untuk semua permintaan (tidak disarankan). Namun implikasi kinerja yang mungkin tetap ada.
maf748
@ GazB Tentu, pernyataan apa pun dengan efek samping dikecualikan dari penggunaannya dalam function. Dalam pengalaman saya, dalam kebanyakan kasus di mana seseorang berpikir mereka membutuhkan pernyataan seperti itu, ini sebenarnya berarti mereka harus memikirkan kembali function- atau setidaknya menolak untuk a procedure. Setidaknya berbicara sendiri. :-)
underscore_d
8

Coba gunakan INSERTalih-alih SELECT INTO:

INSERT @UserData   
SELECT name, location etc.
Noel Abrahams
sumber
5

Pertama-tama buat tabel temp:

Langkah 1:

create table #tblOm_Temp (

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

** Langkah 2: ** Masukkan Beberapa nilai dalam tabel Temp.

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

Langkah 3: Deklarasikan tabel Variabel untuk menyimpan data tabel temp.

declare   @tblOm_Variable table(

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

Langkah 4: pilih nilai dari tabel temp dan masukkan ke dalam variabel tabel.

insert into @tblOm_Variable select * from #tblom_temp

Akhirnya nilai dimasukkan dari tabel temp ke variabel Tabel

Langkah 5: Dapat Memeriksa nilai yang dimasukkan dalam variabel tabel.

select * from @tblOm_Variable
404 tidak ditemukan
sumber
1

OK, Sekarang dengan usaha yang cukup saya bisa memasukkan ke dalam @table menggunakan di bawah ini:

INSERT @TempWithheldTable SELECT
a.SuspendedReason, a.SuspendedNotes, a.SuspendedBy, a.ReasonCode DARI OPENROWSET (BULK 'C: \ DataBases \ WithHeld.csv', FORMATFILE = N'C: \ DataBases \ Format.txt ',
ERR ' N'C: \ Temp \ MovieLensRatings.txt ') SEBAGAI a;

Hal utama di sini adalah memilih kolom untuk disisipkan.

RahulJha
sumber
Saya mendapatkan pesan kompilasi 'Harus mendeklarasikan variabel tabel "@TempWithheldTable"
atreeon
-5

Salah satu alasan untuk menggunakan SELECT INTO adalah memungkinkan Anda menggunakan IDENTITY:

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

Ini tidak akan berfungsi dengan variabel tabel, yang terlalu buruk ...

MOHCTP
sumber
6
Anda dapat mendeklarasikan variabel tabel dengan IDENTITYkolom.
Martin Smith