ВИБІРТЕ В змінну таблиці в 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
Якщо ви "SELECT name, location FOT myTable" в якості значень, які ви будете вставляти в таблицю UserData, не має значення, якщо назви змінних у select вибирають імена з визначення таблиці. Ви вибираєте "ім'я", щоб перейти в змінну UserData "name", але ви вибираєте "location" і якось присвоюєте йому змінну UserData "oldlocation". Чи просто SQL відобразить їх автоматично або він викине якийсь виняток?
Аран Малхолланд

Не має значення назва, лише тип стовпця.
CristiC

5
Нічого собі такого немає сенсу, але в той же час аналізатор почуває себе ображеним :)
Aran Mulholland

Я, здається, не можу це використати в ОЗНАЧЕННЯМИ заяві: посилання gist
Paul-Sebastian Manole

1
Якщо ви не встановите чітко стовпці у викладенні, тоді вони відображаються у порядку, оголошеному в початковому операторі створення таблиці, подібно до виділення *. Отже, розташування в операторі select виводиться на старе розташування в таблиці @userData, оскільки місце розташування знаходиться в положенні 2 в наборі результатів вибору, а старе розташування - це стовпець 2 у визначенні таблиці. Але це ніколи не роби цього. Впорядкування баз стовпців або рядків не слід покладатися. Завжди будьте явні з цього приводу.
абсміти

94

Мета SELECT INTO(за документами, мій акцент)

Щоб створити нову таблицю з значень в іншій таблиці

Але у вас вже є цільова таблиця! Тож те, що ти хочеш

INSERTОператор додає один або кілька нових рядків у таблицю

Значення даних можна вказати наступними способами:

...

Використовуючи SELECTпідзапит для визначення значень даних для одного або кількох рядків, таких як:

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

І в цьому синтаксисі дозволено MyTableбути змінною таблиці.


1
Дуже бажаю, щоб прийнята відповідь включала цю інформацію!
Даві Браун

Я розумію, що MyTable робить це "Недійсне ім'я об'єкта", тому щось не вистачає в цій відповіді.
Майк Флінн

@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


Я не думаю, що це робить копію, якщо ви видалите або оновите з userData, чи не буде вона видалена та оновлена ​​записи в оригінальних таблицях?
атреон

Так, DELETE та UPDATE на CTE будуть змінювати вихідну таблицю до тих пір, поки CTE не посилається на кілька таблиць за допомогою приєднань, об'єднань тощо
nanestev

2
Мінус цього полягає в тому, що ви можете використовувати таблицю CTE лише в наступних командах. Якщо вам потрібно зробити кілька проходів через набір результатів з будь-якої причини, CTE не працюватиме. ОП, схоже, передбачає, що будуть внесені кілька модифікацій, і в цьому випадку це не буде працювати - "Дані в змінній таблиці пізніше будуть використані для вставки / оновлення їх назад у різні таблиці (переважно копіюють ті самі дані з другорядними оновлення). "
Тоні

16

Ви можете спробувати використати тимчасові таблиці ... якщо ви не робите це з програми. (Можливо, запустити це вручну)

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

Ви пропускаєте зусилля, щоб таким чином оголосити таблицю ... Допомагає для adhoc-запитів ... Це створює локальну таблицю темп, яка не буде видимою для інших сеансів, якщо ви не знаходитесь на тому ж сеансі. Можливо, проблема, якщо ви запускаєте запит із програми.

якщо вам потрібен запуск програми, використовуйте змінні, оголошені таким чином:

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;

Редагувати: стільки з вас згадували оновлену видимість до сеансу від з'єднання. Створення тимчасових таблиць - це не варіант для веб-додатків, оскільки сеанси можна використовувати повторно, дотримуючись тимчасових змінних у цих випадках


2
Вибачте, забув згадати, що я не маю прав на СТВОРИТИ СТОЛ.
Індрек

6
Створення темпу має трохи більше витрат.
папараццо

2
використання таблиці темп не завжди безпечно. Наприклад, веб-сервіси. Якщо веб-сервіси з єдиним підключенням обмежують максимальне з'єднання на сервері ТА Protectign SQL трохи більше, тимчасова таблиця існуватиме для ВСЕГО запиту, що проходить, і може замінити когось, хто зараз ним користується.
Франк

12
@Franck - якщо ви використовуєте глобальну таблицю темпів (два хеш-префікса), ви правильні. Однак локальна таблиця тимчасових тем (один хеш-префікс) буде виділена в один сеанс (він же є одним з'єднанням), тому не буде проблем з паралельною валютою, на які ви натякаєтесь, якщо ви не використовуєте єдине з'єднання для всіх запитів (не порадив). Однак можливі наслідки для продуктивності.
maf748

@GazB Звичайно, будь-яке твердження з побічним ефектом виключається з використання в function. На мій досвід, у більшості випадків, коли хтось думає, що їм потрібні такі твердження, це насправді означає, що вони повинні переосмислити свої function- або, принаймні, рефактори procedure. Якщо говорити про себе, принаймні. :-)
підкреслюй_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: Оголосіть змінну таблиці для зберігання даних таблиці темп.

declare   @tblOm_Variable table(

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

Крок 4: виберіть значення з таблиці темп та вставте в змінну таблиці.

insert into @tblOm_Variable select * from #tblom_temp

Нарешті значення вставляється з таблиці темп у змінну таблиці

Крок 5: Чи можна перевірити вставлене значення у змінній таблиці.

select * from @tblOm_Variable

1

Гаразд, зараз, маючи достатньо зусиль, я можу вставити в @table за допомогою наведеного нижче:

Вставити @TempWithheldTable ВИБІР
a.SuspendedReason, a.SuspendedNotes, a.SuspendedBy, a.ReasonCode ВІД OPENROWSET (BULK 'C: \ Databases \ WithHeld.csv', FORMATFILE = N'C: \ \ Format.txt Бази даних »,
файл помилок = N'C: \ Temp \ MovieLensRatings.txt ') AS a;

Головне тут - вибір стовпців для вставки.


Я отримую повідомлення "Потрібно оголосити змінну таблиці" @TempWithheldTable "повідомлення про помилку компіляції
atreeon

-5

Однією з причин використання SELECT INTO є те, що вона дозволяє використовувати IDENTITY:

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

Це не буде працювати зі змінною таблиці, що дуже погано ...


6
IDENTITYОднак ви можете оголосити змінну таблиці зі стовпцем.
Мартін Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.