SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET QUOTED_IDENTIFIER ON; IF OBJECT_ID('[dbo].[FN_SPLIT_INT]') IS NOT NULL
DROP FUNCTION [dbo].[FN_SPLIT_INT]
GO IF OBJECT_ID('[dbo].[FN_SPLIT]') IS NOT NULL
DROP FUNCTION [dbo].[FN_SPLIT]
GO CREATE FUNCTION [dbo].[FN_SPLIT] (
@Text nvarchar(max), -- Text to split
@Delimiter nvarchar(1000) -- Value to split on, try to only pass a single char. See notes for details.
)
/* ------------------------------------------------------------------------------------------------
Purpose: Split text on a common char.
Design Notes:
1) Will trim leading/trailing white space from items.
2) Will omit blank and null items.
3) Compatible from SQL 2005 and onward (see details about [item_int] in return table)
4) Return table item is nvarchar(max) (not bound by string length)
5) Reasonably durable with escape sequences, so if a delimiter has a [,%,_ in it, the patter should still match.
6) Uses a sliding search window, not saving the remaining text on each iteration. However,
saving each item in a temp variable (@item) was faster than using a CTE to temporarily
store the value, which surprised me.
7) Returns the value as an int as well, which is a common use for this function (splitting comma
separated lists of ints). Note that this should be low impact in that if you don't query
against that column since it is a non-persistent computed column (i.e. low overhead).
8) Supports @Delimiter > 1 char, but slower. Note in the unit tests, with text of approximately
10K, 1 char is about 30% faster, hence the big IF block in the code. Plus, the multi-char
delimiter does not scale terribly well. The test with 100,000 records, a 1 char delimiter takes
about 6 seconds while with a 5 char delimiter took 430 seconds (7 minutes!). As such, try to
replace your multi char delimiters with a single char value before calling this function.
Side Note: For what it's worth, I did try an alternative method of saving the remaining
"working text" as a sub string of text so the search would get faster near the end, but overall
it was slower at about 500 seconds. NOTE: This version does not support case sensitivity. See "TODO" comments if you need a case insensitive version Revision history:
---------------------------------------------------------------------------------------------------
Date User Change Description
---------------------------------------------------------------------------------------------------
10/10/2013 Brad Joss (bradjoss@hotmail.com) Initial Public Draft
---------------------------------------------------------------------------------------------------*/
RETURNS @retTable TABLE
(
-- Output table definition
[item] nvarchar(max) COLLATE DATABASE_DEFAULT NOT NULL, -- Since most of the times we split, we are splitting lists of ints, this makes that process easier.
-- Since the column is non persistent it should only be evaluated when requested (low overhead).
[item_int] as (
-- SQL 2012 version, better, use if possible
-- TRY_CONVERT([int], NULLIF([item],'')) -- SQL 2012 Format, faster and safer, but pre-2012 code provided as well... -- Pre SQL 2012 syntax. Not as reliable, so use 2012 when possible by commenting out this CAST and using the TRY_CONVERT above
CAST(
CASE
WHEN LEN(item) > 11 THEN NULL -- LEN OF (-2147483648) is 11. Simple out of bounds checking.
WHEN ISNUMERIC([item]) = 1 AND [item] NOT LIKE '%.%' THEN [item] -- Ensure value conforms to int
ELSE null
END
as int)
)
)
WITH SCHEMABINDING
AS
BEGIN
-- Garbage in, Garbage out. If they did not pass input data, return nothing.
IF RTRIM(ISNULL(@Text,'')) = '' OR RTRIM(ISNULL(@Delimiter,'')) = ''
RETURN DECLARE
@ix bigint -- Current index
, @pix bigint -- Previous index
, @del_len int -- Delimiter length
, @text_len bigint -- Input text length
, @item nvarchar(max) -- Temp item buffer. I tried w/o using CTEs, but this way was faster SELECT @del_len = LEN(@Delimiter)
, @text_len = LEN(@Text) IF @del_len = 1
BEGIN -- CHARINDEX MODE (Much faster than PATINDEX mode)
SELECT @ix = CHARINDEX(@Delimiter, @Text) -- TODO: If you want to implment Case Insensitivity here, wrap both in LOWER()
, @pix = 0 -- No delim found, just return the passed value, trimmed
IF @ix = 0
BEGIN
INSERT INTO @retTable(item)
SELECT LTRIM(RTRIM(@Text)) -- We know this is not null because of the first GIGO check above
END
ELSE
BEGIN
-- Find most of the matches
WHILE @ix > 0
BEGIN
SELECT
-- Get the current value
@item = LTRIM(RTRIM(SUBSTRING(@Text,@pix,(@ix - @pix))))
-- Move previous pointer to end of last found delimiter
, @pix = @ix + @del_len
-- And update the values for next pass though the loop, finding the next match
, @ix = CHARINDEX(@Delimiter, @Text, (@ix + @del_len)) -- TODO: If you want to implment Case Insensitivity here, wrap both in LOWER() IF @item <> '' AND @item IS NOT NULL -- Only save non empty values
INSERT INTO @retTable(item) VALUES (@item)
END -- Get the trailing text
SET @item = LTRIM(RTRIM(SUBSTRING(@Text,@pix,@text_len)))
IF @item <> '' AND @item IS NOT NULL -- Only save non empty values
INSERT INTO @retTable(item) VALUES (@item)
END -- @ix = 0
END
ELSE -- @del_len = 1
BEGIN -- PATINDEX Mode (SLOW!) Try to pass in text that uses single char delimeters when possible DECLARE @del_pat nvarchar(3002) -- Assume 3x @Delimiter + 2, for escaping every character plus wrapper % -- Escape characters that will mess up the like clause, and wrap in wild cards %
SELECT @del_pat = '%' + REPLACE(REPLACE(REPLACE(@Delimiter
, '[','[[]')
, '%','[%]')
, '_', '[_]')
+ '%' SELECT @ix = PATINDEX(@del_pat, @Text) -- TODO: If you want to implment Case Insensitivity here, wrap both in LOWER()
, @pix = 0 -- No delim found, just return the passed value, trimmed
IF @ix = 0
BEGIN
INSERT INTO @retTable(item)
SELECT LTRIM(RTRIM(@Text)) -- We know this is not null because of the first GIGO check above
END
ELSE
BEGIN
-- Find most of the matches
WHILE @ix > 0
BEGIN
SELECT
-- Get the curent Item
@item = LTRIM(RTRIM(SUBSTRING(@Text,@pix,(@ix - @pix))))
-- Move the previous index to the end of the previous delimiter
, @pix = @ix + @del_len
-- And set values for next itteration of the loop, finding the next match
, @ix = PATINDEX(@del_pat, SUBSTRING(@Text, (@ix + @del_len), @text_len)) -- TODO: If you want to implment Case Insensitivity here, wrap both in LOWER() IF @item <> '' AND @item IS NOT NULL -- Only save non empty values
INSERT INTO @retTable(item) VALUES (@item) IF @ix > 0 SET @ix = ((@ix + @pix) - 1) -- -1 since PatIndex is 1 based and Substring is 0 based
END -- Get the trailing text
SET @item = LTRIM(RTRIM(SUBSTRING(@Text,@pix,@text_len)))
IF @item <> '' AND @item IS NOT NULL -- Only save non empty values
INSERT INTO @retTable(item) VALUES (@item)
END -- @ix = 0
END -- @del_len = 1 RETURN
END GO /*
Overloaded version to make splitting comma seperated lists of ints easier.
Note the delimiter is hard coded to comma and that non-int values will be removed.
*/
CREATE FUNCTION [dbo].[FN_SPLIT_INT] (
@Text nvarchar(max) -- Text to split
)
RETURNS TABLE
AS
RETURN SELECT [item_int] -- TODO: Optional add distinct?
FROM [dbo].[FN_SPLIT](@Text, ',') -- Hard coded to comma delimited
WHERE [item_int] IS NOT NULL -- Remove invalid values
GO GRANT REFERENCES, SELECT ON [dbo].[FN_SPLIT] TO [public] AS [dbo]
GRANT REFERENCES, SELECT ON [dbo].[FN_SPLIT_INT] TO [public] AS [dbo]
GO -- Precompile, so performance numbers below are not skewed.
SELECT * INTO #Garbage1 FROM [dbo].[FN_SPLIT]('1,2,3',',')
SELECT * INTO #Garbage2 FROM [dbo].[FN_SPLIT_INT]('1,2,3') DROP TABLE #Garbage1
DROP TABLE #Garbage2
GO --------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------
-- Unit test --
-- Split has been problematic enough for me I thought these tests important. SET NOCOUNT ON DECLARE @TESTS TABLE (
[cnt] int,
[txt] nvarchar(max),
[delim] nvarchar(1000),
[sum_len] int
)
DECLARE @RESULTS TABLE (
[id] int identity(1,1),
[msg] varchar(255) null,
[pass_fail] AS (
CASE
WHEN (ISNULL([expected_count],0) = ISNULL([actual_count],0) AND ISNULL([expected_sum_len],0) = ISNULL([actual_sum_len],0)) THEN 'PASS'
ELSE 'FAIL'
END
),
[runtime] int null,
[expected_count] int null,
[actual_count] int null,
[expected_sum_len] int null,
[actual_sum_len] int null,
[delim] nvarchar(1000),
[txt] nvarchar(max)
) DECLARE @BigText nvarchar(max)
DECLARE @BigTextItemCount int
DECLARE @BigTextSumHash int -- Alternative large volume tests, set to 10 for quick, set to 100K for a real workout
--SELECT @BigTextItemCount = 10, @BigTextSumHash = 11
SELECT @BigTextItemCount = 10000, @BigTextSumHash = 38894
--SELECT @BigTextItemCount = 100000, @BigTextSumHash = 488895 -- Create the hash of big text. I know this code is somewhat ugly, but it creates the large text in
-- about 1 second, as opposed to an itterative concat that took 14 minutes... :-)
;with cte as (
select 9 as [i]
union all
select [i] - 1 FROM cte where [i] > 0
),
crs as (
SELECT ROW_NUMBER() OVER(ORDER BY c1.[i]) as [rn]
FROM cte c1 --
CROSS JOIN cte c2 --
CROSS JOIN cte c3 --
CROSS JOIN cte c4 --
CROSS JOIN cte c5 --
)
SELECT @BigText =
(
(
SELECT '#' + CAST([rn] as nvarchar(32))
FROM crs
WHERE [rn] <= @BigTextItemCount
FOR XML PATH('') , TYPE
).value('.', 'nvarchar(max)')
) -- Most of the tests go here --
INSERT INTO @TESTS (cnt, sum_len, txt, delim)
-- Basic 1-char Delim Tests
SELECT 0, 0, '', ','
UNION ALL SELECT 0, 0, null, ','
UNION ALL SELECT 0, 0, 'a', null
UNION ALL SELECT 0, 0, 'a', ''
UNION ALL SELECT 3, 3, '1,2,3', ','
UNION ALL SELECT 3, 3, ',1,2,3', ','
UNION ALL SELECT 3, 3, '1,2,3,', ','
UNION ALL SELECT 3, 3, ',1,2,3,', ','
UNION ALL SELECT 3, 3, ' , 1 , 2 , 3 , ', ','
UNION ALL SELECT 3, 3, ',,, , 1 , 2 , 3 , ,,,', ','
UNION ALL SELECT 3, 3, 'a, b, c', ','
UNION ALL SELECT 3, 3, 'a,b,c', ','
UNION ALL SELECT 2, 6, 'Cat=Pub', '='
UNION ALL SELECT 1, 1, 'a', ','
UNION ALL SELECT 1, 1, ' a ', ','
-- 1 char Int Tests
UNION ALL SELECT 10, 18, 'a,1,2,-1,-2,b,1.0,-1.0, 3 , -4 ,', ','
-- Basic multi-char delim tests
UNION ALL SELECT 0, 0, '', '<tag>'
UNION ALL SELECT 0, 0, null, '<tag>'
UNION ALL SELECT 0, 0, 'a', null
UNION ALL SELECT 0, 0, 'a', ''
UNION ALL SELECT 3, 3, '1<TaG>2<tag>3', '<tag>' -- Case Insensitivity test 1
UNION ALL SELECT 3, 3, '<tag>1<tag>2<tag>3', '<TaG>' -- Case Insensitivity test 2
UNION ALL SELECT 3, 3, '1<tag>2<tag>3<tag>', '<tag>'
UNION ALL SELECT 3, 3, '<tag>1<tag>2<tag>3<tag>', '<tag>'
UNION ALL SELECT 3, 3, ' <tag> 1 <tag> 2 <tag> 3 <tag> ', '<tag>'
UNION ALL SELECT 3, 3, '<tag><tag><tag> <tag> 1 <tag> 2 <tag> 3 <tag> <tag><tag><tag>', '<tag>'
UNION ALL SELECT 3, 3, 'a<tag> b<tag> c', '<tag>'
UNION ALL SELECT 3, 3, 'a<tag>b<tag>c', '<tag>'
UNION ALL SELECT 2, 6, 'Cat<tag>Pub', '<tag>'
UNION ALL SELECT 1, 1, 'a', '<tag>'
UNION ALL SELECT 1, 1, ' a ', '<tag>'
-- multi char delim Int Tests
UNION ALL SELECT 10, 18, 'a<tag>1<tag>2<tag>-1<tag>-2<tag>b<tag>1.0<tag>-1.0<tag> 3 <tag> -4 <tag>', '<tag>'
-- Delims with escape char % in it
UNION ALL SELECT 0, 0, '', '<t%a%g>'
UNION ALL SELECT 0, 0, null, '<t%a%g>'
UNION ALL SELECT 0, 0, 'a', null
UNION ALL SELECT 0, 0, 'a', ''
UNION ALL SELECT 3, 3, '1<t%a%g>2<t%a%g>3', '<t%a%g>'
UNION ALL SELECT 3, 3, '<t%a%g>1<t%a%g>2<t%a%g>3', '<t%a%g>'
UNION ALL SELECT 3, 3, '1<t%a%g>2<t%a%g>3<t%a%g>', '<t%a%g>'
UNION ALL SELECT 3, 3, '<t%a%g>1<t%a%g>2<t%a%g>3<t%a%g>', '<t%a%g>'
UNION ALL SELECT 3, 3, ' <t%a%g> 1 <t%a%g> 2 <t%a%g> 3 <t%a%g> ', '<t%a%g>'
UNION ALL SELECT 3, 3, '<t%a%g><t%a%g><t%a%g> <t%a%g> 1 <t%a%g> 2 <t%a%g> 3 <t%a%g> <t%a%g><t%a%g><t%a%g>', '<t%a%g>'
UNION ALL SELECT 3, 3, 'a<t%a%g> b<t%a%g> c', '<t%a%g>'
UNION ALL SELECT 3, 3, 'a<t%a%g>b<t%a%g>c', '<t%a%g>'
UNION ALL SELECT 2, 6, 'Cat<t%a%g>Pub', '<t%a%g>'
UNION ALL SELECT 1, 1, 'a', '<t%a%g>'
UNION ALL SELECT 1, 1, ' a ', '<t%a%g>'
UNION ALL SELECT 10, 18, 'a<t%a%g>1<t%a%g>2<t%a%g>-1<t%a%g>-2<t%a%g>b<t%a%g>1.0<t%a%g>-1.0<t%a%g> 3 <t%a%g> -4 <t%a%g>', '<t%a%g>'
-- Delims with escape char _ in it
UNION ALL SELECT 0, 0, '', '<t_ag>'
UNION ALL SELECT 0, 0, null, '<t_ag>'
UNION ALL SELECT 0, 0, 'a', null
UNION ALL SELECT 0, 0, 'a', ''
UNION ALL SELECT 3, 3, '1<t_ag>2<t_ag>3', '<t_ag>'
UNION ALL SELECT 3, 3, '<t_ag>1<t_ag>2<t_ag>3', '<t_ag>'
UNION ALL SELECT 3, 3, '1<t_ag>2<t_ag>3<t_ag>', '<t_ag>'
UNION ALL SELECT 3, 3, '<t_ag>1<t_ag>2<t_ag>3<t_ag>', '<t_ag>'
UNION ALL SELECT 3, 3, ' <t_ag> 1 <t_ag> 2 <t_ag> 3 <t_ag> ', '<t_ag>'
UNION ALL SELECT 3, 3, '<t_ag><t_ag><t_ag> <t_ag> 1 <t_ag> 2 <t_ag> 3 <t_ag> <t_ag><t_ag><t_ag>', '<t_ag>'
UNION ALL SELECT 3, 3, 'a<t_ag> b<t_ag> c', '<t_ag>'
UNION ALL SELECT 3, 3, 'a<t_ag>b<t_ag>c', '<t_ag>'
UNION ALL SELECT 2, 6, 'Cat<t_ag>Pub', '<t_ag>'
UNION ALL SELECT 1, 1, 'a', '<t_ag>'
UNION ALL SELECT 1, 1, ' a ', '<t_ag>'
UNION ALL SELECT 10, 18, 'a<t_ag>1<t_ag>2<t_ag>-1<t_ag>-2<t_ag>b<t_ag>1.0<t_ag>-1.0<t_ag> 3 <t_ag> -4 <t_ag>', '<t_ag>'
-- Semi Evil tests
UNION ALL SELECT 2, 2, 'a~`!@#$%^&*()_+|-=\{}:;"''<>,.?/ b', '~`!@#$%^&*()_+|-=\{}:;"''<>,.?/ ' -- no []
UNION ALL SELECT 2, 2, 'a~`!@#$%^&*()_+|-=\{}[]:;"''<>,.?/ b', '~`!@#$%^&*()_+|-=\{}[]:;"''<>,.?/ ' -- with []
UNION ALL SELECT 2, 2, 'a' + CHAR(10) + CHAR(13) + 'b', CHAR(10) + CHAR(13) -- White space chars
-- Big Text Tests
UNION ALL SELECT @BigTextItemCount,@BigTextSumHash,@BigText, '#'
UNION ALL SELECT @BigTextItemCount,@BigTextSumHash,REPLACE(@BigText,'#', '<tag>'), '<tag>' -- Loop through each of the tests, logging results
DECLARE @txt nvarchar(max) -- Input text
DECLARE @delim nvarchar(1000) -- Input delimiter
DECLARE @cnt int -- Expected count
DECLARE @sum_len int -- Expected sum(len(item))
DECLARE @t_cnt int -- Actual count
DECLARE @t_sum_len int -- Actual sum(len(item))
DECLARE @start datetime -- Test Start time (for performance tracking) DECLARE cur CURSOR FAST_FORWARD FOR
SELECT [cnt],[txt],[delim],[sum_len] FROM @TESTS
OPEN cur
FETCH cur INTO @cnt, @txt, @delim,@sum_len
WHILE @@FETCH_STATUS = 0
BEGIN SELECT @start = GetDate(); -- Execute test
SELECT @t_cnt = count(*), @t_sum_len = SUM(LEN(item))
FROM [dbo].[FN_SPLIT](@txt, @delim) -- Log results
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'TEST', DATEDIFF(ms, @start, GetDate()), @cnt, @t_cnt, @sum_len, ISNULL(@t_sum_len,0), @delim, @txt FETCH cur INTO @cnt, @txt, @delim,@sum_len
END
CLOSE cur
DEALLOCATE cur ----------------------------------------------------------------------------------------------------------------------------------
-- Extra tests that required additional coding
DECLARE @int_test nvarchar(max)
SELECT @int_test = N'a,1,2,-1,-2,b,1.0,-1.0, 3 , -4 ,' -- Basic int test, ensure int's are properly returned
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Tested Ints 1', null, 6, count(*), null, null, ',', @int_test
FROM [dbo].[FN_SPLIT](@int_test, ',')
WHERE [item_int] is not null -- Ensure text value associated with int values maps 1:1
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Tested Ints 2', null, 6, count(*), null, null, ',', @int_test
FROM [dbo].[FN_SPLIT](@int_test, ',')
WHERE CAST([item_int] as nvarchar(max)) = [item]
and item_int is not null -- Split int tests
SELECT @int_test = '1,-2,3'
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 3, count(*), 2, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) SELECT @int_test = '1,a,-2,b,3,c'
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 3, count(*), 2, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) SELECT @int_test = '1, -2, 3' -- Spaces between commas
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 3, count(*), 2, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) SELECT @int_test = ' 1, -2, 3 ' -- Leading/trailing
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 3, count(*), 2, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) SELECT @int_test = '999999999999999,1,-2,-3,-99999999999999999' -- Basic boundry testing
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 3, count(*), -4, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) SELECT @int_test = ' 1.0, -2.0, 3 ' -- Should only return ints
SELECT @start = GetDate();
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Split Int: ' + @int_test, DATEDIFF(ms, @start, GetDate()), 1, count(*), 3, SUM(item_int), '#', @int_test
FROM [dbo].[FN_SPLIT_INT](@int_test) ----------------------------------------------------------------------------------------------------------------------------------
-- Runtime / Performance testing IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2
IF OBJECT_ID('tempdb..#t3') IS NOT NULL DROP TABLE #t3 SELECT @start = GetDate();
SELECT [item] INTO #t1 FROM [dbo].[FN_SPLIT](@BigText, '#')
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Speed 1: Item only', DATEDIFF(ms, @start, GetDate()), null, null, null, null, '#', @BigText SELECT @start = GetDate();
SELECT [item_int] INTO #t3 FROM [dbo].[FN_SPLIT](@BigText, '#')
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Speed 2: Item Int Only', DATEDIFF(ms, @start, GetDate()), null, null, null, null, '#', @BigText SELECT @start = GetDate();
SELECT [item] INTO #t2 FROM [dbo].[FN_SPLIT](@BigText, '#') WHERE [item_int] IS NOT NULL
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'Speed 3: Item With Int Filter', DATEDIFF(ms, @start, GetDate()), null, null, null, null, '#', @BigText IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
IF OBJECT_ID('tempdb..#t2') IS NOT NULL DROP TABLE #t2
IF OBJECT_ID('tempdb..#t3') IS NOT NULL DROP TABLE #t3 ----------------------------------------------------------------------------------------------------------------------------------
/*
-- Ensure test failures work
INSERT INTO @RESULTS ([msg],[runtime],[expected_count],[actual_count],[expected_sum_len],[actual_sum_len],[delim],[txt])
SELECT 'INTENTIONAL FAILURE', null, 1, 2, 3, 4, '', ''
*/ -- Display results
SELECT *
FROM @RESULTS
ORDER BY CASE [pass_fail] WHEN 'FAIL' THEN 0 ELSE 1 END ASC, [id] ASC -- And Total runtime
SELECT SUM(ISNULL(runtime,0)) as [total_runtime] FROM @RESULTS -- Raise errors as needed.
IF (SELECT count(*) FROM @RESULTS WHERE [pass_fail] = 'FAIL') > 0
RAISERROR('Unexpected results. Review results table for details.',18,1)
GO
 SET ANSI_NULLS ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET QUOTED_IDENTIFIER ON;
GO IF OBJECT_ID('[dbo].[PR_FIND]') IS NOT NULL
DROP PROCEDURE [dbo].[PR_FIND]
GO CREATE PROCEDURE [dbo].[PR_FIND]
/* ------------------------------------------------------------------------------------------------
Purpose: Examples (finding self, since we know it exists) EXEC [PR_FIND] '@DisplayLevel'
EXEC [PR_FIND] 'PR_FIND', 0
EXEC [PR_FIND] 'PR_FIND', 1, 50 Revision history:
---------------------------------------------------------------------------------------------------
Date User Change Description
---------------------------------------------------------------------------------------------------
10/11/2013 Brad Joss (bradjoss@hotmail.com) Initial Public Draft
01/20/2014 Brad Joss Fixed line number bug where line numbers were incorrect.
01/23/2014 Brad Joss When fixing the above bug, I saw some items that might
be nice to have, so I added a few features:
- Will now match on name, not just body text. Name can be fully qualified
since functionally it will do an OBJECT_ID() match.
- Display more details in run summary including total matches
and a better breakdown of where time was spent while searching.
- Display match_count and name_match in summary results.
---------------------------------------------------------------------------------------------------*/
(
@TextToFind nvarchar(max), -- Pattern to search on
@DisplayLevel tinyint = 1, -- 0 = Object Summary Only, 1 = Windowed Results, 2 = Full text
@Lead int = 40, -- Amount of text to show the left and right of the result in Windowed mode
@SearchJobsToo bit = 1, -- When true, search SQL Agent Job Steps
@IncludeObjects nvarchar(max) = null, -- Comma separated list of objects scope search to
@ExcludeObjects nvarchar(max) = null -- Comma separated list of objects exempt from search
)
AS
BEGIN
SET NOCOUNT ON DECLARE @id int -- Object ID
, @name nvarchar(max) -- Full Object Name
, @Text nvarchar(max) -- Object Text
, @DisplayText nvarchar(max) -- Text to Output
, @index int -- index of start of display window (@match_index - @Lead)
, @match_index int -- Actual index where we found the match
, @matchCount int -- Matches found for the text
, @spanLen int -- Length of display window
, @lenText int -- Curent LEN(@Text)
, @lenTextToFind int -- LEN(@TextToFind)
, @StartTime DateTime -- Runtime Start
, @OriginalTextToFind nvarchar(max) -- Backup of what is being searched on before we adjust it
, @create_date datetime -- Object create date
, @modify_date datetime -- Object mod date
, @type_desc nvarchar(60) -- Object type
, @total_lines int -- Runing total of found new lines
, @current_line_number int -- Line number current match is found on (starting from CREATE statement)
, @total_start_time datetime -- Start time of the SP call, for kicks
, @skip_lines int -- When we skip a body of text, keep track of line count for skipped text
, @new_line nvarchar(max) -- Character(s) to seek when counting new lines
, @scan_time int -- Time it took to scan for matches
, @passed_object_id int -- If they passed in a full object name, let's know about it here... -- Just to make sure we are keeping the code well optimzed, display runtimes
SELECT @total_start_time = GetDate() -- Get this before we do any transformations on the text
SELECT @passed_object_id = OBJECT_ID(@TextToFind) -- Backup what is being searched on so when we display it it doesn't look funny
SELECT @OriginalTextToFind = @TextToFind -- Wrap the text in wild card wrappers and remove %%, setting to LOWER() so all matches will be case insenstive later on
SELECT @TextToFind = REPLACE('%' + LOWER(@TextToFind) + '%', '%%','%') -- If they passed something that maps 1:1 to an object, escape out the bracets so we match on object name,
-- not character array patterns when searching on text. The actual name match will be based on object_id
IF @passed_object_id IS NOT NULL
SELECT @TextToFind = REPLACE(@TextToFind,'[','[[]') -- Even if we actually use 10/13, the way we are counting should still work.
-- If you move to more than 1 newline character, then the character count will have
-- to be factored into the delta counts (e.g. (LEN() - LEN(REPLACE()))/LEN(@new_line))
SELECT @new_line = CHAR(10) -- Parmeter checks
IF ISNULL(@DisplayLevel,-1) NOT IN (0,1,2)
SET @DisplayLevel = 1 -- Default to windowed mode
IF @Lead IS NULL OR @Lead < 0
SET @Lead = 40 -- Default lead lenght
IF @SearchJobsToo IS NULL
SET @SearchJobsToo = 1
IF RTRIM(@IncludeObjects) = ''
SET @IncludeObjects = NULL
IF RTRIM(@ExcludeObjects) = ''
SET @ExcludeObjects = NULL -- Table to store the matched objects
DECLARE @oids TABLE (
[id] int, -- [object_id]
[name] nvarchar(512),
[schema_name] nvarchar(512),
[full_name] as (
ISNULL('[' + [schema_name] + '].', '') + '[' + [name] + ']'
),
[create_date] datetime,
[modify_date] datetime,
[type_desc] nvarchar(60),
[txt] nvarchar(max),
[name_match] bit default(0),
[match_count] int null
) -- Table to store what objects to return
DECLARE @scope_objects TABLE (
[object_id] int,
[include] bit not null default(0)
) -- If they have indicated they want to filter by object name, create a list of
-- valid objects to be searched.
IF @IncludeObjects IS NOT NULL OR @ExcludeObjects IS NOT NULL
BEGIN
-- Explicitly omit these items
;with cte as (
SELECT o.id
FROM sysobjects o
INNER JOIN [dbo].[FN_SPLIT](@ExcludeObjects,',') f
on (UPPER(o.name) LIKE LTRIM(RTRIM(UPPER([item])))) -- Case insensitive non-wildcard match, so we can actually match on a specific object name if need be
AND RTRIM([item]) <> ''
)
INSERT INTO @scope_objects ([object_id],[include])
SELECT DISTINCT [id], 0
FROM cte
WHERE [id] IS NOT NULL IF @@ROWCOUNT = 0
SELECT @ExcludeObjects = NULL -- Later, we check to see if we should filter based on @ExcludeObjects and @IncludeObjects nullness -- Scope search to only include these items
;with cte as (
SELECT o.id
FROM sysobjects o
INNER JOIN [dbo].[FN_SPLIT](@IncludeObjects,',') f
on (UPPER(o.name) LIKE LTRIM(RTRIM(UPPER([item])))) -- Case insensitive non-wildcard match, so we can actually match on a specific object name if need be
AND RTRIM([item]) <> ''
)
INSERT INTO @scope_objects ([object_id],[include])
SELECT DISTINCT [id], 1
FROM cte
WHERE [id] IS NOT NULL IF @@ROWCOUNT = 0
SELECT @IncludeObjects = NULL -- Later, we check to see if we should filter based on @ExcludeObjects and @IncludeObjects nullness
ELSE
BEGIN
-- If they have indicated that the want to include and exclude at the same time
-- check for object overlap, and default to exclude the item so we can allow a
-- pattern like:
-- Show me all where "aaa%", except "aaa_111"
DELETE FROM @scope_objects
WHERE [include] = 1
AND [object_id] IN (
SELECT [object_id]
FROM @scope_objects
WHERE [include] = 0
) -- If items were deleted, recheck to see if there are any includes left
IF @@ROWCOUNT > 0
IF NOT EXISTS (SELECT * FROM @scope_objects WHERE [include] = 1)
SELECT @IncludeObjects = NULL, @ExcludeObjects = NULL -- Later, we check to see if we should filter based on @ExcludeObjects and @IncludeObjects nullness
END
END -- @IncludeObjects IS NOT NULL OR @ExcludeObjects IS NOT NULL -- Find matches
INSERT INTO @oids (id, name, [schema_name], [type_desc], txt, [create_date], [modify_date], [name_match])
select distinct c.id, c.name, [schema_name], [type_desc], c.txt, [create_date], [modify_date],
CASE
-- Substring of a name is what was passed
WHEN LOWER(name) LIKE @TextToFind THEN 1
WHEN
(
-- Fully qualified name was passed
@passed_object_id IS NOT NULL
AND
c.id = @passed_object_id
) THEN 1
ELSE 0 END
from [dbo].[VW_OBJ_TXT] c
-- That case insensitive match our search text
where
(
LOWER(c.[txt]) like @TextToFind -- Body match
OR
LOWER(name) LIKE @TextToFind -- Name match
OR
(
-- In case they pass in "[dbo].[MyObject]" versus "dbo.MyObject" versus "MyObject"
-- Try to give them clues as to what they may be missing out on
@passed_object_id IS NOT NULL
AND
c.id = @passed_object_id
)
)
-- And are either in our include list, or no list was passed
and
(
@IncludeObjects is null
OR
c.id IN (select [object_id] from @scope_objects where [include] = 1)
)
-- And are not in our exclude list, or no list was passed
and
(
@ExcludeObjects is null
OR
c.id NOT IN (select [object_id] from @scope_objects where [include] = 0)
) -- If they have indicated to search job text, do so here.
IF @SearchJobsToo = 1
BEGIN
INSERT INTO @oids (id, name, [schema_name], [type_desc], txt, [create_date], [modify_date], [name_match])
SELECT DISTINCT
(-1 * ROW_NUMBER()OVER(ORDER BY j.name, js.step_name)), -- Since job_id's are not int, job_step_id might be confusing, get arbitrary negative number
ISNULL('JOB: ' + j.name, 'Unknown Job') + ISNULL(', STEP: ' + js.step_name, 'Unknown Step'),
'job',
'SQL Agent Job Step',
js.command, -- Job Step Text
j.date_created,
j.date_modified,
CASE
WHEN LOWER(j.name) LIKE @TextToFind THEN 1
WHEN LOWER(js.step_name) LIKE @TextToFind THEN 1
ELSE 0
END
FROM msdb.dbo.sysjobs j
JOIN msdb.dbo.sysjobsteps js
ON js.job_id = j.job_id
WHERE
(
LOWER(js.command) like @TextToFind -- Case insensitive
OR
LOWER(j.name) LIKE @TextToFind
OR
LOWER(js.step_name) LIKE @TextToFind
)
END SELECT @scan_time = DATEDIFF(ms, @total_start_time, GetDate()) IF @DisplayLevel > 0
BEGIN
-- Horizontal rules to break up the results
DECLARE @C_OBJECT_HR nvarchar(max) = '/******************************************************************************/'
DECLARE @C_MATCH_HR nvarchar(max) = '--------------------------------------------------------------------------------' -- Cache this value once before we enter into loop
SELECT @lenTextToFind = LEN(@TextToFind) - 2 -- -2 = Trimming the %
IF @lenTextToFind < 0
SELECT @lenTextToFind = 0 PRINT @C_OBJECT_HR -- Loop though the results, getting the multiple matches within the body of the text
DECLARE DispCur CURSOR FAST_FORWARD FOR
SELECT
o.id,
[full_name],
o.txt,
create_date,
modify_date,
type_desc
from @oids o
ORDER BY LOWER([full_name]) ASC OPEN DispCur
FETCH DispCur INTO @id, @name, @Text, @create_date, @modify_date, @type_desc WHILE @@FETCH_STATUS = 0
BEGIN
-- Object match template, add details here to display information about the match per object
PRINT 'ID: ' + CAST(@id as varchar(64))
PRINT 'NAME: ' + @name
PRINT 'TYPE: ' + @type_desc
PRINT 'CREATED: ' + CAST(@create_date as nvarchar(max)) + ', MODIFIED: ' + CAST(@modify_date as nvarchar(max))
PRINT 'SEARCH: "' + @OriginalTextToFind + '"'
PRINT @C_MATCH_HR IF @DisplayLevel = 1 -- Windowed display mode
BEGIN
SELECT @StartTime = GetDate() -- For the search time of this one object (not the whole routine), for kicks
SELECT @index = PATINDEX(@TextToFind, LOWER(@Text)) -- Search for our matching pattern
SELECT @match_index = @index
SELECT @matchCount = 0
SELECT @DisplayText = ''
SELECT @total_lines = 0 -- Find all occurences of the pattern --
WHILE @index > 0
BEGIN
-- Get the count of new line characters, then adding on matches from previous blocks of text
SELECT @current_line_number = (LEN(SUBSTRING(@Text, 1, @index)) - LEN(REPLACE(SUBSTRING(@Text, 1, @index), @new_line, ''))) -- Buffer the common search values in variables
SELECT @matchCount = @matchCount + 1
SELECT @lenText = LEN(@Text)
-- Set the start @index in bounds
SELECT @index = CASE
WHEN @index > @Lead THEN @index - @Lead
ELSE 0
END
-- Size of the display window
SELECT @spanLen = LEN(@TextToFind) + (2*@Lead) -- If the search window is longer than the search text, narrow it
IF @spanLen + @index > @lenText
SELECT @spanLen = @lenText - @index -- Display code snippet --
SELECT @DisplayText = @DisplayText + '
Match ' + CAST(@matchCount as varchar(32)) + ' on line ' + CAST((@current_line_number + @total_lines) as varchar(32)) + ' within ' + @name + '
' + @C_MATCH_HR + '
...' + SUBSTRING(@Text, @index, @spanLen) + '...
' -- If the search window covered to the end of the text, end searching
IF (@match_index + @Lead) >= @lenText
SELECT @index = 0
ELSE
BEGIN
-- Keep track of how many lines will be skipped by advancing the seek start by the window length
SELECT @skip_lines = LEN(SUBSTRING(@Text, @match_index, @Lead)) - LEN(REPLACE(SUBSTRING(@Text, @match_index, @Lead), @new_line, '')) -- Else rescope the text to be searched to what remains and re-search
SELECT @Text = SUBSTRING
(
@Text,
@match_index + @Lead,
@lenText - (@match_index + @Lead)
)
SELECT @index = PATINDEX(@TextToFind, LOWER(@Text)) -- Find the next match
SELECT @match_index = @index
SELECT @total_lines = @total_lines + @current_line_number + @skip_lines -- Keep running total of line numbers
END
END -- While (finding all matches in object) IF @matchCount = 0
SELECT @DisplayText = @DisplayText + 'No body matches found, name match only.' -- Footer template, displayed at the end of each object that matches
SELECT @DisplayText = @DisplayText + '
' + @C_MATCH_HR + '
"' + @OriginalTextToFind + '" Found '
+ CAST(@matchCount as varchar(32)) + ' Time' + (CASE WHEN @matchCount = 1 THEN '' ELSE 's' END) + ' within ' + @name + ' in '
+ CAST(DATEDIFF(ms, @StartTime, GetDate()) as varchar(32)) + 'ms
' EXEC PR_PRINT @DisplayText UPDATE @oids SET [match_count] = @matchCount WHERE [id] = @id END -- @DisplayLevel = 1
ELSE -- Mode 2
BEGIN
-- ELSE Display full code --
EXEC PR_PRINT @Text
END PRINT @C_OBJECT_HR FETCH DispCur INTO @id, @name, @Text, @create_date, @modify_date, @type_desc
END
CLOSE DispCur
DEALLOCATE DispCur
END -- @DisplayLevel > 0 -- Display summary at the bottom so we have match counts --
-- I would prefer this to be at the top, but I like the match count...
SELECT
[id],
CONVERT(varchar(19), [modify_date], 120) as [modify_date],
[type_desc],
[full_name],
[name_match],
[match_count]
from @oids t
ORDER BY LOWER(t.name) ASC DECLARE @Message nvarchar(max)
DECLARE @TotalRuntime int
DECLARE @TotalMatches int SELECT @TotalMatches =
(SELECT SUM(match_count) FROM @oids)
+
(SELECT COUNT(*) FROM @oids where [name_match] = 1); SELECT @TotalRuntime = DATEDIFF(ms, @total_start_time, GetDate())
SELECT @Message = 'Search completed. '
+ 'Found ' + CAST(@TotalMatches as nvarchar(max)) +' match' + CASE WHEN @TotalMatches = 1 THEN '' ELSE 'es' END + '. '
+ CAST(@scan_time as nvarchar(max)) +'ms Scan Time. '
+ CAST((@TotalRuntime - @scan_time) as nvarchar(max)) + 'ms Format Time. '
+ 'Total Runtime: ' + CAST((@TotalRuntime + 500)/1000 as nvarchar(max)) + ' seconds.' -- + 500 so we round up at 1/2 second
PRINT ''
PRINT @Message
END
GO GRANT EXECUTE ON [dbo].[PR_FIND] TO [public] AS [dbo]
GO
 IF OBJECT_ID('dbo.PR_PRINT') IS NOT NULL
DROP PROCEDURE dbo.PR_PRINT
GO CREATE PROCEDURE [dbo].[PR_PRINT]
(
@txt NVARCHAR(MAX) -- Text to print out
)
AS /*
This was originally posted on SQLServerCentral.com at
http://www.sqlservercentral.com/scripts/Print/63240/ Modifed by Brad Joss 10/11/13 to break on space as well This procedure is designed to overcome the limitation
in the SQL print command that causes it to truncate strings
longer than 8000 characters (4000 for nvarchar) in SQL Server
management studio. It will print the text passed to it in substrings smaller than 4000
characters. If there are carriage returns (CRs) or new lines (NLs in the text),
it will break up the substrings at the carriage returns and the
printed version will exactly reflect the string passed. If there are insufficient line breaks in the text, it will
print it out in blocks of 4000 characters with an extra carriage
return at that point. If it is passed a null value, it will do virtually nothing. NOTE: This is substantially slower than a simple print, so should only be used
when actually needed.
*/ SET NOCOUNT ON DECLARE
@cur_end BIGINT, -- track the length of the next substring
@offset tinyint, -- tracks the amount of offSET needed
@pg_sz int, -- size of printing window
@char_idx bigint, -- index of the next newline character in the window
@temp_char_idx bigint, -- to avoid having to substring/reverse the window twice, save the reverse index of a found space here
@start_idx int, -- try to break on a known character combination
@txt_len bigint -- current lenght of the text, basically a cache since we potentially will need it twice in the loop SET @pg_sz = 4000 -- Set window size to 4000 characters -- If size is in bounds (ie, small text), just print it and exit
IF LEN(@txt) <= @pg_sz
BEGIN
PRINT @txt
RETURN
END SET @txt = replace( replace(@txt, char(13) + char(10), char(10)) , char(13), char(10)) -- Standardize what a new line looks like to char(10)
SELECT @txt_len = LEN(@txt) WHILE @txt_len > 1
BEGIN -- Try to break on a new line
SET @char_idx = CHARINDEX(CHAR(10), @txt) -- If we can't find a new line, try to break on a space where the space is near
-- the end of the current page of text
IF NOT (@char_idx between 1 AND @pg_sz)
BEGIN
-- Get the size of the page of text
SELECT @char_idx = CASE WHEN (@txt_len < @pg_sz) THEN @txt_len ELSE @pg_sz END -- Look for the last space character in the page of text
SET @temp_char_idx = CHARINDEX(' ', REVERSE(SUBSTRING(@txt, 1, @char_idx))) -- If found, set the position of the found character on the non-reversed string
IF @temp_char_idx > 0
SET @char_idx = (@char_idx - @temp_char_idx) + 1 -- +1 here since we -1 later on
ELSE -- Indicate character is still not found
SET @char_idx = 0
END -- Try to break on a known char (newline or space) --
IF @char_idx between 1 AND @pg_sz
BEGIN
-- Since we know the character we are breaking on is white space (new line or space)
-- don't print it (hence the -1)
SET @cur_end = @char_idx - 1
SET @offset = 2
END
ELSE
BEGIN
-- Else, just break at the window size.
SET @cur_end = @pg_sz
SET @offset = 1
END -- Print the section
PRINT SUBSTRING(@txt, 1, @cur_end) -- Remote the printed text from what remains to be printed.
SET @txt = SUBSTRING(@txt, @cur_end+@offset, 1073741822)
SELECT @txt_len = LEN(@txt) END /*End While loop*/ -- Print any leftovers
PRINT @txt GO GRANT EXECUTE ON [dbo].[PR_PRINT] TO [public]
GO PRINT 'Basic Test:'
EXEC dbo.PR_PRINT 'aaa bbb ccc d' PRINT ''
PRINT 'More Complicated Test:' DECLARE @BigText nvarchar(max)
DECLARE @WindowSize int
SET @WindowSize = 4000
SELECT @BigText = CAST(REPLICATE('a',@WindowSize-1) as nvarchar(max))
+ CAST(' ' as nvarchar(max))
+ CAST(REPLICATE('b',@WindowSize-1) as nvarchar(max))
+ CAST(CHAR(10) as nvarchar(max))
+ CAST(REPLICATE('c',@WindowSize-1) as nvarchar(max))
+ CAST('xxx' as nvarchar(max))
+ CAST(REPLICATE('d',@WindowSize-1)as nvarchar(max)) EXEC dbo.PR_PRINT @BigText
GO
IF OBJECT_ID('VW_OBJ_TXT') IS NOT NULL
DROP VIEW [dbo].[VW_OBJ_TXT]
GO CREATE VIEW [dbo].[VW_OBJ_TXT]
/*******************************************************************************
* Name : dbo.VW_OBJ_TXT
* Author : bradjoss@hotmail.com
* Purpose : Helper view to make searching thorough code easier
******************************************************************************
* Change Date Change By Change DSC
* ----------- ------------- --------------------------------------
* 10/05/2012 Brad Joss Initial Draft
* 01/24/2014 Brad Joss Return records with null text bodies, like tables.
Nixed cast on get from syscomments, it was unnecessary.
*******************************************************************************/
AS
with cte as
(
select
o.[object_id] as [id],
o.[schema_id],
SCHEMA_NAME(o.[schema_id]) as [schema_name],
o.name,
o.type,
o.type_desc,
o.create_date,
o.modify_date,
(
(
-- Concatenate together all the sections of code that make up a given object
SELECT c2.[text]
FROM syscomments c2 (nolock)
WHERE c2.[id] = o.[object_id]
ORDER BY colid
FOR XML PATH('') , TYPE
).value('.', 'nvarchar(max)')
) AS [txt]
from sys.objects o
)
SELECT
cte.*
/*
-- These extend the potency of the view for doing code comparison. Since this view is only
-- being posted as part of another suite of code, I have commmented them out. Uncomment if
-- they would be useful to you in some way.
, LEN([txt]) AS [txt_len] -- The name swap is to contend with cases where the object text may be the same but the name
-- differs, as might be the case with an automatic constraint name.
, CHECKSUM(REPLACE(txt, name, '##NAME##')) as [checksum]
*/
FROM cte
-- WHERE [txt] IS NOT NULL -- Allow returing of objects w/o bodies
GO -- Ensure it compiles
select top 3 * from [VW_OBJ_TXT]
GO

https://www.codeproject.com/Tips/667730/T-SQL-Search-SQL-Code

EXEC [dbo].[PR_FIND] 'Sys_Role'

T-SQL代码搜索的更多相关文章

  1. 使用Phoenix将SQL代码移植至HBase

    1.前言 HBase是云计算环境下最重要的NOSQL数据库,提供了基于Hadoop的数据存储.索引.查询,其最大的优点就是可以通过硬件的扩展从而几乎无限的扩展其存储和检索能力.但是HBase与传统的基 ...

  2. EntityFramework 7 如何查看执行的 SQL 代码?

    EF 其他版本:EntityFramework 如何查看执行的 SQL 代码? 在 EF7 中,并没有 Context.Database.Log 属性访问方式,但改变更加强大了,我们可以使用下面方式配 ...

  3. EntityFramework 如何查看执行的 SQL 代码?

    在 VS 调试的时候,如果我们项目中使用的是 EntityFramework,查看 SQL 执行代码就不像 ADO.NET 那样直观了,我们需要设置下,可以参考下: How can I log the ...

  4. Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询

    Visual Studio Entity Framework (EF) 生成SQL 代码 性能查询     SQL 中,有SQL Server Profiler可以用来查询性能以及查看外部调用的SQL ...

  5. iOS开发数据库篇—SQL代码应用示例

    iOS开发数据库篇—SQL代码应用示例 一.使用代码的方式批量添加(导入)数据到数据库中 1.执行SQL语句在数据库中添加一条信息 插入一条数据的sql语句: 点击run执行语句之后,刷新数据 2.在 ...

  6. MySQL查询今天/昨天/本周、上周、本月、上个月份数据的sql代码

    MySQL查询本周.上周.本月.上个月份数据的sql代码 作者: 字体:[增加 减小] 类型:转载 时间:2012-11-29我要评论 MySQL查询的方式很多,下面为您介绍的MySQL查询实现的是查 ...

  7. WEBUS2.0 In Action - [源代码] - C#代码搜索器

    最近由于工作的需要, 要分析大量C#代码, 在数万个cs文件中搜索特定关键词. 这是一项非常耗时的工作, 用Notepad++要运行接近半个小时. 于是我利用WEBUS2.0 SDK创建了一个代码搜索 ...

  8. C# 必应代码搜索

    微软宣布推出必应代码搜索服务,暂时只支持 C# 语言,日后将支持更多代码语言. Visual Studio 用户安装必应搜索插件之后可使用该服务来简化编程任务.Visual Studio 与 MSDN ...

  9. [源代码] - C#代码搜索器 - 续

    在前文 [源代码] - C#代码搜索器 中我开发了一个代码搜索器. 我对其做的最后改动是将索引保存到磁盘中, 以备今后使用. 如今, 我在工作中又接到一项新任务: 有一个大项目, 其中10个负责数据访 ...

  10. 同样的一句SQL语句在pl/sql 代码块中count 没有数据,但是直接用SQl 执行却可以count 得到结果

    pl/sql 代码块: SELECT count(distinct t2.so_nbr) INTO v_count2 FROM KFGL_YW_STEP_qd t2 WHERE t2.partitio ...

随机推荐

  1. UVA_401:Palindromes

    AC:Time(29ms)     C++ 4.8.2 #include<stdio.h> #include<string.h> char * mirstr = "A ...

  2. UVa 10285【搜索】

    UVa 10285 哇,竟然没超时!看网上有人说是记忆化搜索,其实不太懂是啥...感觉我写的就是毫无优化的dfs暴力....... 建立一个坐标方向结构体数组,每个节点dfs()往下搜就好了. #in ...

  3. 1176. Two Ends

    题目链接地址:http://soj.me/1176 题目大意:两头取数.第一个人随机取,第二个人用贪婪算法(每次都取大的),求两人取数在第一个人赢的情况下的最大分差.使用贪婪算法时,如果左右两边相等, ...

  4. iptables 伪装(Masquerading)

    「偽装」是一种特殊的SNAT操作:将来自其它电脑的包的来源位址改成自己的位址:请注意,由於入替的来源位址是自动決定的(执行SNAT的主机的IP位址).所以,如果它改变了,仍在持续中的旧连線将会失效.「 ...

  5. spring boot activiti 整合

    1.pom.xml <dependency> <groupId>org.activiti</groupId> <artifactId>activiti- ...

  6. [转]安卓加固之so文件加固

    一.前言 最近在学习安卓加固方面的知识,看到了jiangwei212的博客,其中有对so文件加固的两篇文章通过节加密函数和通过hash段找到函数地址直接加密函数,感觉写的特别好,然后自己动手实践探索s ...

  7. js面向对象(对象/类/工厂模式/构造函数/公有和原型)

    https://www.cnblogs.com/sandraryan/ 什么是对象 js中一切都是对象(有行为和特征).js允许自定义对象,也提供了内建对象(string date math等) 对象 ...

  8. Hammersley-Clifford定理证明

    Proof of Hammersley-Clifford TheoremProof of Hammersley-Clifford Theorem依赖知识定义1定义2证明过程反向证明(吉布斯分布=> ...

  9. H3C 配置Basic NAT

  10. java声明异常(throws)

    在可能出现异常的方法上声明抛出可能出现异常的类型: 声明的时候尽可能声明具体的异常,方便更好的处理. 当前方法不知道如何处理这种异常,可将该异常交给上一级调用者来处理(非RuntimeExceptio ...