2010-05-27 31 views
12

Có vẻ như #temptables được tạo bằng SQL động thông qua phương thức chuỗi EXECUTE có phạm vi khác và không thể được tham chiếu bởi các câu lệnh SQL "cố định" trong cùng một thủ tục được lưu trữ. Tuy nhiên, tôi có thể tham khảo bảng tạm thời được tạo bởi câu lệnh SQL động trong SQL động sau nhưng có vẻ như thủ tục đã lưu không trả về kết quả truy vấn cho ứng dụng khách gọi trừ khi SQL được sửa.T-SQL SQL động và Bảng tạm thời

Kịch bản 2 bảng đơn giản: Tôi có 2 bảng. Hãy gọi chúng là Đơn hàng và Vật phẩm. Thứ tự có khóa chính của OrderId và các mục có khóa chính của ItemId. Items.OrderId là khóa ngoài để xác định thứ tự cha. Đơn đặt hàng có thể có từ 1 đến n Mục.

Tôi muốn có thể cung cấp giao diện loại "trình tạo truy vấn" rất linh hoạt cho người dùng để cho phép người dùng chọn mục mà anh muốn xem. Tiêu chí lọc có thể dựa trên các trường từ bảng Items và/hoặc từ bảng Order cha. Nếu một mục đáp ứng điều kiện bộ lọc bao gồm và điều kiện trên thứ tự gốc nếu có, mục phải được trả về trong truy vấn cũng như thứ tự gốc.

Thông thường, tôi cho rằng, hầu hết mọi người sẽ xây dựng một kết nối giữa bảng Mục và bảng Thứ tự gốc. Thay vào đó, tôi muốn thực hiện 2 truy vấn riêng biệt. Một để trả lại tất cả các mặt hàng đủ điều kiện và mặt hàng kia để trả lại tất cả các Đơn đặt hàng gốc riêng biệt. Lý do là hai lần và bạn có thể hoặc có thể không đồng ý. Lý do đầu tiên là tôi cần truy vấn tất cả các cột trong bảng thứ tự gốc và nếu tôi đã thực hiện một truy vấn đơn lẻ để tham gia bảng Orders đến bảng Items, tôi sẽ lặp lại thông tin Order nhiều lần. Vì thường có một số lượng lớn các mục trên mỗi Đơn đặt hàng, tôi muốn tránh điều này vì nó sẽ dẫn đến nhiều dữ liệu hơn được chuyển cho một khách hàng chất béo. Thay vào đó, như đã đề cập, tôi muốn trả về hai bảng riêng lẻ trong một tập dữ liệu và sử dụng hai bảng bên trong để cư trú một đối tượng Custom Order và child Items tùy chỉnh. (Tôi không biết đủ về LINQ hoặc Entity Framework. Tôi xây dựng các đối tượng của tôi bằng tay). Lý do thứ hai tôi muốn trả lại hai bảng thay vì một là vì tôi đã có một thủ tục khác trả về tất cả các mục cho một OrderId nhất định cùng với thứ tự cha và tôi muốn sử dụng cùng một phương pháp 2 bảng để tôi có thể tái sử dụng mã máy khách để điền các đối tượng Order và Client tùy chỉnh của tôi từ 2 datatables được trả về.

Những gì tôi đã hy vọng để làm được điều này:

Xây dựng một chuỗi SQL động trên Client mà gia nhập bảng đơn đặt hàng vào bảng Items và các bộ lọc thích hợp trên mỗi bảng theo quy định của bộ lọc tùy chỉnh được tạo trên Winform ứng dụng khách hàng chất béo. SQL xây dựng trên máy khách đã có thể nhìn một cái gì đó như thế này:

TempSQL = " 

    INSERT INTO #ItemsToQuery 
     OrderId, ItemsId 
    FROM 
     Orders, Items 
    WHERE 
     Orders.OrderID = Items.OrderId AND 
     /* Some unpredictable Order filters go here */ 
     AND 
     /* Some unpredictable Items filters go here */ 
    " 

Sau đó, tôi sẽ gọi một thủ tục lưu trữ,

CREATE PROCEDURE GetItemsAndOrders(@tempSql as text) 
    Execute (@tempSQL) --to create the #ItemsToQuery table 

SELECT * FROM Items WHERE Items.ItemId IN (SELECT ItemId FROM #ItemsToQuery) 

SELECT * FROM Orders WHERE Orders.OrderId IN (SELECT DISTINCT OrderId FROM #ItemsToQuery) 

Vấn đề với phương pháp này là bảng #ItemsToQuery, vì nó là được tạo bởi SQL động, không thể truy cập được từ 2 SQL tĩnh sau và nếu tôi thay đổi các SQL tĩnh thành động, không có kết quả nào được truyền lại cho trình khách chất béo.

3 xung quanh tôi suy nghĩ nhưng tôi nhìn cho một tốt hơn:

1) SQL đầu tiên có thể được thực hiện bằng cách thực hiện SQL động được xây dựng từ các khách hàng. Các kết quả sau đó có thể được chuyển thành một bảng cho một phiên bản sửa đổi của thủ tục được lưu trữ ở trên. Tôi quen thuộc với việc truyền dữ liệu bảng dưới dạng XML. Nếu tôi đã làm điều này, proc được lưu trữ sau đó có thể chèn dữ liệu vào một bảng tạm thời bằng cách sử dụng một SQL tĩnh, bởi vì nó được tạo ra bởi SQL động, sau đó có thể được truy vấn mà không có vấn đề.(Tôi cũng có thể điều tra để chuyển thông số loại Bảng mới thay vì XML.) Tuy nhiên, tôi muốn tránh chuyển các danh sách có khả năng lớn đến một thủ tục được lưu trữ.

2) Tôi có thể thực hiện tất cả các truy vấn từ ứng dụng khách.

Đầu tiên sẽ là một cái gì đó như thế này:

SELECT Items.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter) 
SELECT Orders.* FROM Orders, Items WHERE Order.OrderId = Items.OrderId AND (dynamic filter) 

này vẫn cung cấp cho tôi với khả năng tái sử dụng của khách hàng mặt mã đối tượng-dân của tôi, vì các đơn đặt hàng và mục tiếp tục được trả lại trong hai bảng khác nhau.

Tôi có cảm giác, rằng tôi có thể có một số tùy chọn sử dụng loại dữ liệu Bảng trong proc được lưu trữ của tôi, nhưng điều đó cũng mới đối với tôi và tôi sẽ đánh giá cao một chút cho ăn thìa.

Nếu bạn thậm chí đã quét những gì tôi viết, tôi ngạc nhiên, nhưng nếu có, tôi sẽ đánh giá cao bất kỳ suy nghĩ nào của bạn về cách thực hiện điều này tốt nhất.

+0

TLDR: http://www.urbandictionary.com/define.php?term=TLDR –

Trả lời

17

bạn cần tạo bảng đầu tiên sau đó nó sẽ có sẵn trong sql động

này hoạt động

create table #temp3 (id int) 
exec ('insert #temp3 values(1)') 

select * from #temp3 

này sẽ không hoạt

exec ('create table #temp2 (id int) 
    insert #temp2 values(1)') 

select * from #temp2 

Nói cách khác:

  1. tạo bảng temp

  2. thực hiện proc

  3. chọn từ bảng temp

Đây là Complete dụ

create proc prTest2 @var varchar(100) 
as 
exec (@var) 
go 

create table #temp (id int) 

exec prTest2 'insert #temp values(1)' 

select * from #temp 
+0

Tôi nghĩ rằng điều này cũng hoạt động: chèn vào #temptable exec ('select ?? from ??'); –

+4

vấn đề là khi chúng tôi không biết các định nghĩa cột, làm thế nào về sau đó? – Muflix

0

bộ Kết quả từ SQL động được trả lại cho khách hàng. Tôi đã làm điều này khá nhiều.

Bạn đang đúng về các vấn đề với chia sẻ dữ liệu thông qua các bảng và biến tạm thời và những thứ tương tự giữa SQL và SQL động mà nó tạo ra.

Tôi nghĩ rằng trong cố gắng để có được tạm thời bảng làm việc của bạn, bạn đã có thể có một số điều nhầm lẫn, bởi vì bạn chắc chắn có thể lấy dữ liệu từ một SP mà thực thi SQL động:

USE SandBox 
GO 

CREATE PROCEDURE usp_DynTest(@table_type AS VARCHAR(255)) 
AS 
BEGIN 
    DECLARE @sql AS VARCHAR(MAX) = 'SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''' + @table_type + '''' 
    EXEC (@sql) 
END 
GO 

EXEC usp_DynTest 'BASE TABLE' 
GO 

EXEC usp_DynTest 'VIEW' 
GO 

DROP PROCEDURE usp_DynTest 
GO 

Ngoài ra:

USE SandBox 
GO 

CREATE PROCEDURE usp_DynTest(@table_type AS VARCHAR(255)) 
AS 
BEGIN 
    DECLARE @sql AS VARCHAR(MAX) = 'SELECT * INTO #temp FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''' + @table_type + '''; SELECT * FROM #temp;' 
    EXEC (@sql) 
END 
GO 

EXEC usp_DynTest 'BASE TABLE' 
GO 

EXEC usp_DynTest 'VIEW' 
GO 

DROP PROCEDURE usp_DynTest 
GO 
+0

nếu bạn tạo bảng tạm thời trong proc nó sẽ không hoạt động, bạn cần phải tạo bảng tạm thời đầu tiên, sau đó bạn có thể cư nó trong proc..see cũng ví dụ của tôi – SQLMenace

+0

@SQLMenace - tôi thấy những gì bạn đang nói. Quan điểm của tôi là bạn CÓ THỂ trả về các bộ từ SQL động (và chúng có thể sử dụng các bảng tạm thời của riêng chúng và trả về từ chúng). Tôi sẽ thêm một ví dụ thứ hai. –

2

Tôi thực sự khuyên bạn nên đọc qua http://www.sommarskog.se/arrays-in-sql-2005.html

Cá nhân tôi thích phương pháp chuyển danh sách văn bản được phân cách bằng dấu phẩy, sau đó phân tích cú pháp ing nó với văn bản để chức năng bảng và tham gia vào nó. Cách tiếp cận bảng tạm thời có thể hoạt động nếu bạn tạo nó trước tiên trong kết nối. Nhưng nó cảm thấy một chút lộn xộn hơn.

+1

Tôi sẽ sớm chuyển XML hơn CSV. Mặc dù tiết lộ nhiều hơn, nó cho phép sự linh hoạt để sửa đổi và vượt qua các cột bổ sung. Và SQL đã biết cách phân tích cú pháp XML. Nhưng tôi đã xem ví dụ về việc chuyển một tập dữ liệu khách hàng sang biến bảng phía máy chủ. Rất sạch sẽ. Mặc dù vậy, ít hấp dẫn hơn bảng tạm thời IMHO, đó là một cách tiếp cận ít có khả năng mở rộng hơn. – ChadD

3
DECLARE @DynamicQuery NVarchar(MAX) 
    Set @DynamicQuery='Select * into #temp from (select * from tablename) alias 
    select * from #temp 
    drop table #temp' 
    exec sp_executesql @DynamicQuery 

HOẶC Phương pháp thứ 2.
Điều này sẽ hiệu quả.Bạn cần phải chăm sóc thêm biến toàn cầu.

IF OBJECT_ID('tempdb..##temp2') IS NULL 
BEGIN 
    exec ('create table ##temp2 (id int) 
     insert ##temp2 values(1)') 

    select * from ##temp2 

END 

Đừng quên xóa ## temp2 đối tượng mannually một khi mục tiêu của bạn sẽ đạt được.

IF OBJECT_ID('tempdb..##temp2') IS NOT NULL 
DROP Table ##temp2 

Lưu ý: Dont sử dụng phương pháp này nếu bạn không biết cấu trúc đầy đủ về cơ sở dữ liệu.

Các vấn đề liên quan