一位同事和我编写了这个存储过程,它记录了wiki标记中的数据库表,用于ScrewTurn wiki系统。最初,我没有光标就写了它,因为直到今天我才知道如何使用它!
我从基本上是你在下面看到的内容的组合开始。我会为每一行选择一列,其中该列是该行的整个wikimarkup。这完美地运作,但我想在结果之前和之后打印文本。我通过使用一些工会来攻击它。我会将标题与结果集合并,然后将所有这些与页脚结合起来。但是,我必须在每一行之间插入一行文本,这就是我不知道没有使用光标的部分。简而言之:
如何在每个结果行之前选择一堆带有硬编码行的记录?
在我的情况下,每行需要以|-
行开头。
set ansi_nulls on
go
set quoted_identifier on
go
alter procedure DocTable
@TableName varchar(256)
as
begin
set nocount on;
declare @WikiDocData table
(
Name nvarchar(256),
[Type] nvarchar(256),
Nullable nvarchar(256),
[Default] nvarchar(256),
[Identity] nvarchar(256),
[Description] nvarchar(max)
)
insert into @WikiDocData
select
c.name as Name,
tp.name +
' (' +
(case when c.max_length = -1 then 'MAX' else convert(nvarchar(256),c.max_length) end) +
', ' +
convert(nvarchar(256), c.scale) +
', ' +
convert(nvarchar(256), c.[precision]) + ')'
as [Type (L,S,P)],
(case when c.is_nullable = 1 then 'Yes' else '' end) as Nullable,
isnull(d.[definition], '') as [Default],
(case when c.is_identity = 1 then 'Yes' else '' end) as [Identity],
convert(nvarchar(max),isnull(p.value, '')) as [Description]
from
sys.tables t
inner join sys.columns c on t.object_id = c.object_id
left join sys.extended_properties p on c.object_id = p.major_id and c.column_id = p.minor_id
inner join sys.types tp on c.system_type_id = tp.system_type_id
left join sys.default_constraints d on c.default_object_id = d.object_id and c.column_id = d.parent_column_id
where
t.[name] = @TableName
and tp.name <> 'sysname'
order by
t.object_id,
c.column_id
/* Dear reader, if you know how to do this without a cursor, please let me know! */
-- Output header
print '{| cellpadding="4" cellspacing="0" border="1"'
print '! Name !! Type (L,S,P) !! Nullable !! Default !! Identity !! Description'
-- Output each row and row separator
declare @WikiRow nvarchar(max)
declare @GetWikiRow cursor
set @GetWikiRow = cursor for
select
'| ' +
Name + ' || ' +
[Type] + ' || ' +
Nullable + ' || ' +
[Default] + ' || ' +
[Identity] + ' || ' +
[Description]
from
@WikiDocData
open @GetWikiRow fetch next from @GetWikiRow into @WikiRow while @@fetch_status = 0
begin
print '|-'
print @WikiRow
fetch next from @GetWikiRow into @WikiRow
end
close @GetWikiRow
deallocate @GetWikiRow
-- Output footer
print '|}'
end
go
目前正在运作。在aspnet_Membership上运行时,它只打印出以下内容:
{| cellpadding="4" cellspacing="0" border="1"
! Name !! Type (L,S,P) !! Nullable !! Default !! Identity !! Description
|-
| ApplicationId || uniqueidentifier (16, 0, 0) || || || ||
|-
| UserId || uniqueidentifier (16, 0, 0) || || || ||
|-
| Password || nvarchar (256, 0, 0) || || || ||
|-
| PasswordFormat || int (4, 0, 10) || || ((0)) || ||
|-
| PasswordSalt || nvarchar (256, 0, 0) || || || ||
|-
| MobilePIN || nvarchar (32, 0, 0) || Yes || || ||
|-
| Email || nvarchar (512, 0, 0) || Yes || || ||
|-
| LoweredEmail || nvarchar (512, 0, 0) || Yes || || ||
|-
| PasswordQuestion || nvarchar (512, 0, 0) || Yes || || ||
|-
| PasswordAnswer || nvarchar (256, 0, 0) || Yes || || ||
|-
| IsApproved || bit (1, 0, 1) || || || ||
|-
| IsLockedOut || bit (1, 0, 1) || || || ||
|-
| CreateDate || datetime (8, 3, 23) || || || ||
|-
| LastLoginDate || datetime (8, 3, 23) || || || ||
|-
| LastPasswordChangedDate || datetime (8, 3, 23) || || || ||
|-
| LastLockoutDate || datetime (8, 3, 23) || || || ||
|-
| FailedPasswordAttemptCount || int (4, 0, 10) || || || ||
|-
| FailedPasswordAttemptWindowStart || datetime (8, 3, 23) || || || ||
|-
| FailedPasswordAnswerAttemptCount || int (4, 0, 10) || || || ||
|-
| FailedPasswordAnswerAttemptWindowStart || datetime (8, 3, 23) || || || ||
|-
| Comment || ntext (3000, 0, 0) || Yes || || ||
|}
LittleBobbyTables回答的新代码(它更短但涉及大量字符串连接,并且当标记中有超过8000个字符时无法打印):
set ansi_nulls on
go
set quoted_identifier on
go
alter procedure DocTable
@TableName varchar(256)
as
begin
set nocount on;
-- Output header
print '{| cellpadding="4" cellspacing="0" border="1"'
-- Output each row and row separator
declare @WikiRow nvarchar(max)
set @WikiRow = '! Name !! Type (L,S,P) !! Nullable !! Default !! Identity !! Description'
select
@WikiRow = @WikiRow +
char(10) + '|- ' + char(10) + '| ' +
c.name + ' || ' +
tp.name +
' (' +
(case when c.max_length = -1 then 'MAX' else convert(nvarchar(256),c.max_length) end) +
', ' +
convert(nvarchar(256), c.scale) +
', ' +
convert(nvarchar(256), c.[precision]) + ')' + ' || ' +
(case when c.is_nullable = 1 then 'Yes' else '' end) + ' || ' +
isnull(d.[definition], '') + ' || ' +
(case when c.is_identity = 1 then 'Yes' else '' end) + ' || ' +
convert(nvarchar(max),isnull(p.value, ''))
from
sys.tables t
inner join sys.columns c on t.object_id = c.object_id
left join sys.extended_properties p on c.object_id = p.major_id and c.column_id = p.minor_id
inner join sys.types tp on c.system_type_id = tp.system_type_id
left join sys.default_constraints d on c.default_object_id = d.object_id and c.column_id = d.parent_column_id
where
t.[name] = @TableName
and tp.name <> 'sysname'
order by
t.object_id,
c.column_id
print @WikiRow
-- Output footer
print '|}'
end
go
答案 0 :(得分:4)
这是打印长varchar(max)变量的例程(它要求CRLF之间的距离不要大于PRINT的最大阈值才能工作,因为它基本上接受字符串并将其移动到“行”中的缓冲区中,然后当缓冲区超过4000个字符时打印缓冲区):
CREATE PROCEDURE [usp_PrintLongSQL]
@sql varchar(max)
AS
BEGIN
DECLARE @CRLF AS varchar(2)
SET @CRLF = CHAR(13) + CHAR(10)
DECLARE @input AS varchar(max)
SET @input = @sql
DECLARE @output AS varchar(max)
SET @output = ''
WHILE (@input <> '')
BEGIN
DECLARE @line AS varchar(max)
IF CHARINDEX(@CRLF, @input) > 0
SET @line = LEFT(@input, CHARINDEX(@CRLF, @input) - 1) + @CRLF
ELSE
SET @line = @input
IF LEN(@input) - LEN(@line) > 0
SET @input = RIGHT(@input, LEN(@input) - LEN(@line))
ELSE
SET @input = ''
SET @output = @output + @line
IF LEN(@output) > 4000
BEGIN
PRINT @output
SET @output = ''
END
END
IF @output <> ''
PRINT @output
END
我个人更喜欢使用它,因为它使许多其他代码更简单,更通用而没有游标(例如,可以进入视图或内联表值函数的代码更可重用)。
答案 1 :(得分:2)
更新:Per Cade Roux和Chris,打印超过8000个字符时不起作用。我将此作为警告。
您可以使用变量重复添加行。试试这个:
-- Output header
print '{| cellpadding="4" cellspacing="0" border="1"'
print '! Name !! Type (L,S,P) !! Nullable !! Default !! Identity !! Description'
-- Output each row and row separator
declare @WikiRow nvarchar(max)
set @WikiRow = ''
select @WikiRow = @WikiRow +
'|- ' + char(10) + '| ' +
Name + ' || ' +
[Type] + ' || ' +
Nullable + ' || ' +
[Default] + ' || ' +
[Identity] + ' || ' +
[Description] + char(10)
from
@WikiDocData
print left(@WikiRow, len(@WikiRow) - 1)
-- Output footer
print '|}'
答案 2 :(得分:1)
可以使用SQL Server 2012或更高版本中的Offset Fetch子句来完成此操作。
使用AdventureWorks Production.Products表...
DECLARE @Output varchar(8000) = '';
-- 'Print' function only prints 8000 non-unicode chars max. Let's print 10 at a time. Use Fetch Next with Offset. (Sql Svr 2012+)
DECLARE @rowNum int = 0;
DECLARE @numRows int;
SELECT @numRows = count(ProductID) from Production.Products;
WHILE @rowNum < @numRows
BEGIN
SELECT @Output = @Output + '
IF (@someVariable = ''' + ProductNumber + ''') BEGIN; RETURN ''' + ProductName + '''; END;'
FROM Production.Products
ORDER BY ProductID
OFFSET @rowNum ROWS FETCH NEXT 10 ROWS ONLY; -- 10 rows at a time so can print without fear of truncation.
PRINT @Output;
SET @Output = ''; -- reset for next set of rows
SET @rowNum = @rowNum + 10;
END
答案 3 :(得分:-1)
如何在每行之前选择一堆带有硬编码字符串的记录?
select '|-I am a hardcoded string with a newline following'
+ char(10) + a.foo as foo
from bar a;
也就是说,只需将硬编码字符串连接到您已选择的列上即可。用新行字符(char(10))分隔它们,或者对于DOS / Windows,使用回车换行符(char(13)+ char(10))。
编辑:感谢所有指出catenation运算符为“+”的人,而不是“||”在T-SQL中。