|
我正在尝试从SQL Server的主表中创建多个表。例如:9 w! Q0 p7 f7 v. e# C
主表看起来像8 k1 } `4 O# m* ]3 ?1 F O( x
A 1
* l: c1 R$ P! t+ k; s: LA 2( R( q5 n$ f- |0 ]% ^+ F
A 3
; Q+ p' [5 t# U* ^, P9 Z1 }4 h6 fB 4% m+ M2 x. F9 M, c: S( B
B 5
; t5 s/ b' B; j r; l9 B7 ZB 6
3 k. d9 s% d/ Q- E输出应如下所示:$ I5 A+ n! e/ Y
表A:2 V; C4 m2 P4 N7 u+ c5 s
A 1* b& g6 w" k/ e& G5 o1 G3 Y
A 2
2 U l9 h, B" TA 3
' J' C9 P7 Z$ ]: M8 C2 l表B:
8 z$ ~) g1 R8 aB 4
* q2 D! t4 o/ I- Q" MB 5 / n0 c- ~# t0 y
B 6
6 |# l$ y7 B' h4 P$ I- |主表每周更新一次,因此可以使用不同的字母。因此,我想创建一个动态查询,该查询将根据有多少个不同的n自动将主表分为“ n”个不同的表,并根据第n个值命名该表。; U/ C. q8 E: y1 E& @
& g/ b5 o. V) G, m- P4 I解决方案:) G4 ~ H+ F7 p; f( K) U4 u/ n$ P
% [% g7 L7 [. e# E. ~
0 I+ d! v v7 d d. r
; R" k1 C8 P: T 是的,它是可以实现的,但是Erland4 \+ V0 `1 |8 ?
Sommarskog的《诅咒与祝福》动态SQL
% J3 h8 X3 C+ b) t1 _/ \% P5 Q' Z# Q
8 I; f G; d) `创建表@tbl
" H# r( Q( K+ w这里的愿望是创建一个表,该表的名称在运行时确定。
/ _( a0 D. Q* ^如果我们只看一下反对在存储过程中使用动态SQL的论点,那么其中很少有真正适用的论点。如果存储过程中具有静态CREATE
6 p* o0 q$ `" r* N8 K: E% yTABLE,则运行该过程的用户必须具有创建表的权限,因此动态SQL不会更改任何内容。计划缓存显然与它无关。等等。- u/ e/ S* }7 z) }6 R" A
但是:为什么呢?你为什么想做这个? 如果要在应用程序中动态创建表,那么您将错过有关数据库设计的一些基础知识。
6 [9 D3 L# P' |" M# Q8 J/ \3 m在关系数据库中,表和列的集合应该是恒定的。它们可能会随着新版本的安装而发生变化,但不会在运行时发生变化。) W. _7 G3 b- O6 d2 |& w C
有时,当人们这样做时,似乎他们想为临时表构造唯一的名称。这是完全不必要的,因为这是SQL Server的内置功能。如果你说:* M- v j$ Z8 w' P
创建表#nisse(一个int NOT NULL)
+ _* f, C, _( O7 O那么幕后的实际名称将更长一些,并且其他连接都将无法看到此#nisse实例。& u2 I* }% u6 I5 v+ k2 J6 V" P
如果要创建一个用户唯一的永久表,但又不想保持连接状态,因此不能使用临时表,那么最好创建一个所有客户端都可以共享的表,但是在第一列是客户端专用的密钥。我将在文章如何在存储过程之间共享数据中更详细地讨论此方法。
& I/ y4 t& {- b
0 w$ f+ D- V# `, Y7 Y4 D" I. x' O使用内联参数化表值函数的可能解决方案(如果需要,可以使用存储过程):- i& W' H9 F& b2 h& M+ {" A, Z
CREATE FUNCTION dbo.fxnExample (@Parameter1 NVARCHAR(1))
9 {3 d5 w% \! i3 T5 W# q' Y1 ?7 c1 uRETURNS TABLE
! Z# k- E: S& Z3 h1 RAS
' p2 [5 l. c% G6 {8 T# |) D7 ARETURN
* N+ \% X2 x C(- H+ s7 ?+ i5 T4 z, p, o( U# t3 t
SELECT id, value5 |$ N( M( h" w" P: M
FROM TableName
" q. q6 j5 d# |4 F. O WHERE id = @Parameter11 P3 K2 V1 T& | |
)4 c( y# n; A# _; a+ O0 A
-- Usage Example
0 T+ m" h4 p% e$ H0 }SELECT * FROM dbo.fxnExample('A') -- only data from 'A'
: r6 o- w, R8 J$ ySELECT * FROM dbo.fxnExample('B') -- only data from 'B'
" \) s5 T3 w5 _$ q. k编辑$ c/ x# C; o5 m# I& ^/ X5 g8 O
您可以为此使用视图,并将它们传递给用户。如果您仍然希望表可以随意更改代码,那么您应该了解一下。为什么要使用视图,因为表仍然是其中之一,因此您会获得可以模仿多个表的动态视图。同样,当数据将在主表中更新时,您的所有视图都将立即获取它,而无需更新/插入。' ?6 c* r; c$ I! Z, X
SqlFiddleDemo& P+ ?3 J# l( ?4 `. z" q5 b
DBFiddle演示(已更新)0 L* F1 N# V: V0 Q5 A( S9 c
CREATE TABLE main_tab(suffix NVARCHAR(10) NOT NULL, val INT);% D- B- B7 G" [/ [
INSERT INTO main_tab(suffix, val)
- j- A( j4 g: y& F* i0 xVALUES ('A', 1), ('A', 2), ('A', 3),. r3 }7 O# B ]+ D4 v9 d+ j2 e
('B', 4), ('B', 5), ('B', 6),
& X# O6 }" P) R ('C', 7), ('C', 8), ('C', 9);6 N3 |, A$ J4 m4 } M
0 S( {% U3 I" k' Y: b
/* Get list of suffixes */: J$ J1 B3 @ o* u. D5 R4 S6 V
SELECT suffix,1 s1 S: \/ z, h" s4 h
[row_id] = ROW_NUMBER() OVER(ORDER BY suffix)
0 H# H8 W& w/ }* cINTO #temp
$ Q, v& g0 @# VFROM main_tab
! ~, l% d# X4 q& W* |7 S% h2 NGROUP BY suffix;1 r' _+ m3 F0 B. y
DECLARE @name_suffix NVARCHAR(100),3 H: b4 |4 s0 q3 L
@sql NVARCHAR(MAX),; D! e3 Q% U3 d+ @
@view_name NVARCHAR(MAX),
: m% Y+ B" ?0 n/ B t, N @index INT = 1,
- b. M5 ? F' U! P @total INT = (SELECT COUNT(*) FROM #temp);
; {3 g: V5 ?& R$ B. H$ N2 M, x% \/* I used simple while loop but you can change to CURSOR if needed */
/ I' ~" f" s: x; K0 v0 LWHILE (@index <= @total)
7 ~0 p0 t- ^4 B$ W* F9 \: JBEGIN
1 _' z& ]" o' o! A; | SELECT @name_suffix = suffix
1 ~' l/ I; Z9 Q/ L' J' L& {2 Z0 T FROM #temp
|: f8 X+ D" T% }5 W WHERE row_id = @index;
3 a& v. t2 a z& M' [* A1 s8 c SELECT @sql = 6 @6 w' p5 Z. R7 g I+ [ w
N'CREATE VIEW [dbo].[View@name_suffix]; m3 l/ j$ v5 C+ v6 S0 ^. j
AS$ r, h3 ?* q+ [2 C8 j" W+ ~* ^3 ]2 D
SELECT
: A+ E& I/ X# P/ f8 o# J t.suffix,; x7 R& d4 M- k% I+ D
t.val
6 Q' V( p: |4 a! G FROM [dbo].[main_tab] t
8 j) n- h( X; Y& U+ c% B WHERE t.suffix = ''@name_suffix''/ a) x0 J$ @8 `* D# F
WITH CHECK OPTION'2 w2 C1 U' K; Z8 t; S
SELECT
) h& w5 _+ F9 M7 |/ _* M @view_name = REPLACE('[dbo].[View@name]', '@name', @name_suffix)7 n+ H- b+ e$ ?2 f
,@sql = REPLACE(@sql, '@name_suffix', @name_suffix)7 T/ \! ~% [2 G3 }. h8 ^
/* Check if view exists, if not create one */
; c* x( k1 P8 i* ~& Y: x /* Instead of EXEC you can use EXEC [dbo].[sp_executesql]& y" R$ l, J* b. Q) z$ i
and pass params explicitly */
. r6 j: ~: o) {. c7 A( r, u IF OBJECT_ID(@view_name, 'V') IS NULL
" P; m" Q4 N* h+ w% y EXEC(@sql)
, o$ D1 Y( S0 o SET @index += 1;* K& @' i! S/ V+ F/ O' a3 K: w" k/ ~/ b
END
' ?, T5 u/ F# @& k6 x" H/* Check if you can query views */! J# }7 B" m* A- B# ^) ?' I A
SELECT *5 _ I; Z x1 C# j$ _
FROM ViewA;
( R' r2 P2 T* j5 GSELECT *
+ [1 I) w$ N I) l4 I, p5 {& tFROM ViewB;3 f5 [- f d: m
SELECT *) L& |$ U8 G6 `8 k, W* b, r w2 R
FROM ViewC; |
|