6.2 ±êÁ¿UDF
±êÁ¿UDF·µ»Øµ¥¸ö£¨±êÁ¿£©Öµ¡£¿ÉÒÔÔÚÔÊÐíʹÓñêÁ¿±í´ïʽ£¨scalar expression£©µÄµØ·½Ê¹ÓñêÁ¿UDF¡£ÀýÈç²éѯ¡¢Ô¼Êø¡¢¼ÆËãÁеȡ£±êÁ¿UDFÒªÇóÂú×ãÏÂÃæÕ⼸¸öÓï·¨ÒªÇó£º
n ±ØÐë°üº¬BEGIN/END¿éÒÔ¶¨Ò庯ÊýµÄÖ÷Ìå¡£
n µ÷ÓÃʱ±ØÐëÏÞ¶¨¼Ü¹¹£¨³ý·ÇÏñ´æ´¢¹ý³Ìµ÷Ò»Ñù±»EXECµ÷Óã¬ÈçEXEC myFunction 3, 4£©¡£
n µ÷ÓÃʱ²»ÔÊÐíºöÂÔ¿ÉÑ¡²ÎÊý£¨ÓÐĬÈÏÖµµÄ²ÎÊý£©£»»òÕߣ¬ÖÁÉÙΪËüÃÇÖ¸¶¨DEFAULT¹Ø¼ü×Ö¡£
ÏÂÃæ½éÉÜT-SQLºÍCLR UDF¡£
T-SQL±êÁ¿UDF
µ±²Ù×÷µÄÖ÷Òª³É±¾À´×ÔÓÚ»ùÓÚ¼¯ºÏµÄÊý¾Ý²Ù×÷¶ø²»Êǹý³ÌÂß¼ºÍ¼ÆËãʱ£¬T-SQL UDFͨ³£Òª±ÈCLR UDF¿ì¡£²»½öUDFÊÇÕâÑù£¬ÆäËûÀàÐ͵ijÌÐòÒ²ÊÇÈç´Ë¡£´´½¨UDFʱ£¬ÔÚº¯ÊýÍ·Ö¸¶¨Ãû³Æ¡¢¶¨ÒåÊäÈë²ÎÊý¡¢¶¨Òå·µ»ØÖµµÄÊý¾ÝÀàÐÍ¡£×÷Ϊһ¸ö±êÁ¿UDFµÄʾÀý£¬ÏÂÃæµÄ´úÂë´´½¨fn_ConcatOrdersº¯Êý£¬Ëü½ÓÊÕ¿Í»§ID×÷ΪÊäÈë²¢·µ»Ø´®Áª¸Ã¿Í»§µÄOrderIDµÃµ½µÄ×Ö·û´®¡£
SET NOCOUNT ON;
USE Northwind;
GO
IF OBJECT_ID('dbo.fn_ConcatOrders') IS NOT NULL
DROP FUNCTION dbo.fn_ConcatOrders;
GO
CREATE FUNCTION dbo.fn_ConcatOrders
(@cid AS NCHAR(5)) RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @orders AS VARCHAR(8000);
SET @orders = '';
SELECT @orders = @orders + CAST(OrderID AS VARCHAR(10)) + ';'
FROM dbo.Orders
WHERE CustomerID = @cid;
RETURN @orders;
END
GO
º¯ÊýÏÈÉùÃ÷±äÁ¿ @orders²¢³õʼ»¯Îª¿Õ×Ö·û´®¡£º¯ÊýÖеIJéѯʹÓÃÁËÒ»¸öÌØÊâµÄSELECT¸³ÖµÓï·¨¡£ËüɨÃè·ûºÏÌõ¼þµÄÐУ¬Ã¿Ò»Ðж¼Îª @orders±äÁ¿¸³Öµ¡£¸ÃÖµÊÇͨ¹ý´®Áª×îÐ嵀 @ordersÄÚÈݺ͵±Ç°ÐеÄOrderIDÖµ²¢ÓÃÒ»¸ö·ÖºÅ×÷Ϊ·Ö¸ô·ûµÃµ½µÄ¡£
ÖØÒª ¸Ã²éѯ²»±£Ö¤´®ÁªµÄ˳Ðò¡£OrderID½«°´SQL ServerɨÃèÊý¾ÝµÄÎïÀí˳Ðò½øÐд®Áª¡£ÔÚÕâÑùµÄ²éѯÖУ¬²»ÒªÒÀÀµORDER BY×Ӿ䡣Èç¹ûÄãÖ¸¶¨ÁËORDER BY×Ӿ䣬SQL Server²»»á²úÉú´íÎ󣬵«Ëü²»±£Ö¤ÔÚ¸³ÖµÇ°¶ÔÊý¾ÝÅÅÐò¡£
ͬÑù£¬Î¢ÈíҲûÓÐÕýʽµÄÎĵµÃèÊö¾ÛºÏ´®Áª£¨aggregate concatenation£©¼¼Êõ£¨ÎÞÂÛÊÇ·ñʹÓÃORDER BY×Ӿ䣩¡£ÕâÀïËùÃèÊöµÄÐÐΪ½ö½öÊÇ»ùÓÚ¹Û²ìµÃµ½µÄ£¬ÎÒ»¹Î´·¢ÏÖ²»Ê¹ÓÃORDER BYʱ»áʧ°Ü¡£µ«Òª¼Çס£¬¹Ù·½²»±£Ö¤ËµËùÓзûºÏÌõ¼þÐеÄÔªËØ¶¼»á±»´®Áª£¬ËùÒÔÄã×îºÃ±ÜÃâÔÚ²úÆ·´úÂëÖÐÍêÈ«ÒÀÀµÕâÏî¼¼Êõ¡£
Òª²âÊÔfn_ConcatOrdersº¯Êý£¬ÔËÐÐÏÂÃæµÄ²éѯ£¬ËüÉú³ÉµÄÊä³öÒÔ¼ò»¯ÐÎʽÏÔʾÔÚ±í6-1ÖС£
SELECT CustomerID, dbo.fn_ConcatOrders(CustomerID) AS Orders
FROM dbo.Customers;
±í6-1 Ϊÿ¸ö¿Í»§´®Áª¶©µ¥ID¸öµÃµ½µÄ½á¹û(±»¼ò»¯)
|
CustomerID |
Orders |
|
ALFKI |
10643;10692;10702;10835;10952;11011; |
|
ANATR |
10308;10625;10759;10926; |
|
ANTON |
10365;10507;10535;10573;10677;10682;10856; |
|
AROUT |
10355;10383;10453;10558;10707; 10741;10743;10768;10793;10864;10920; 10953;11016; |
|
BERGS |
10278;10280;10384;10444;10445;10524;10572;10626; 10654;10672;10689;10733;10778;10837; 10857;10866;10875;10924; |
|
BLAUS |
10501;10509;10582;10614;10853;10956;11058; |
|
BLONP |
10265;10297;10360;10436;10449; 10559;10566;10584;10628;10679;10826; |
|
BOLID |
10326;10801;10970; |
|
BONAP |
10331;10340;10362;10470;10511;10525;10663;10715; 10730;10732;10755;10827;10871;10876;10932;10940;11076; |
|
BSBEV |
10289;10471;10484;10538; 10539;10578;10599;10943;10947;11023; |
|
¡ |
¡ |
ÔÚSQL Server 2005ÖУ¬Äã²»±ØÔÙʹÓÃÕâÖÖ·½·¨ÊµÏÖ×Ö·û´®´®Áª¡£Äã¿ÉÒÔʹÓÃFOR XML PATHÑ¡Ï²¢ÓÃÒ»¸ö¿Õ×Ö·û´®×÷ΪÆäÊäÈ룬¾ÍÏñÕâÑù£º
SET NOCOUNT ON;
USE Northwind;
GO
SELECT CustomerID,
(SELECT CAST(OrderID AS VARCHAR(10)) + ';' AS [text()]
FROM dbo.Orders AS O
WHERE O.CustomerID = C.CustomerID
ORDER BY OrderID
FOR XML PATH('')) AS Orders
FROM dbo.Customers AS C;
ÕâÑùÄã¾Í¿ÉÒÔÍêÈ«¿ØÖÆ´®ÁªµÄ˳ÐòÁË¡£
ÔÚSQL Server 2005ÖÐʹÓÃÓû§¶¨Òå¾ÛºÏº¯Êý£¨UDA£©Ò²¿ÉÒÔ½â¾öÕâ¸öÎÊÌâ¡£µ«Ê¹ÓÃUDAÄ㽫ÎÞ·¨¿ØÖÆ´®ÁªµÄ˳Ðò£¬ÇÒ´®ÁªµÄ×Ö·û´®±»ÏÞÖÆÎª8000¸ö×Ö½Ú¡£¹ØÓÚUDAµÄ¸ü¶àÐÅÏ¢£¬Çë²Î¿¼Inside T-SQL Querying¡£
Íê³Éºó£¬ÔËÐÐÏÂÃæµÄ´úÂë½øÐÐÇåÀí£º
IF OBJECT_ID('dbo.fn_ConcatOrders') IS NOT NULL
DROP FUNCTION dbo.fn_ConcatOrders;
ÐÔÄÜÎÊÌâ
µ±Äã°ÑÍⲿ±íµÄÊôÐÔ×÷ΪÊäÈëÌṩ¸ø±êÁ¿UDFʱ£¬ÔÚ²éѯÖе÷ÓÃÕâ¸öº¯ÊýµÄ³É±¾·Ç³£¸ß£¬ÄãÓ¦¸ÃÇå³þÕâÒ»µã¡£ÉõÖÁµ±º¯ÊýÖ»°üº¬Ò»¸ö´øÓбêÁ¿±í´ïʽµÄreturnbb ×Ó¾äʱ£¬ËüÒ²²»ÊÇÄÚÁª£¨inline£©º¯Êý¡£ÖðÐе÷Óøú¯ÊýµÄ¿ªÏú»áµ¼Ö·dz£¸ßµÄ³É±¾¡£ÔËÐÐÒ»¸ö¼òµ¥µÄÐÔÄܲâÊԾͿÉÒÔ·¢ÏÖ£¬Ïà¶ÔÓÚÄÚÁª±í´ïʽ£¨inline expression£©£¬ÔÚ²éѯÖÐʹÓÃUDFµÄ³É±¾·Ç³£¸ß¡£
ÔÚÔËÐÐÐÔÄܲâÊÔ֮ǰ£¬ÒªÈ·±£ÔÚÊý¾Ý¿âÖÐÒѾ°üº¬ÁËNums±í¡£ÎÒÔÚµÚ1ÕÂÌṩÁË´´½¨ºÍÌî³äNums±íµÄ´úÂë¡£ÔÚSQL Server Management Studio £¨SSMS£©ÖÐÆôÓÃÖ´Ðкó·ÅÆú½á¹ûÑ¡ÏÕâÑùÄãµÄͳ¼Æ½á¹û½«²»°üº¬Éú³ÉÊä³öËù»¨·ÑµÄʱ¼ä¡£
ÏÈ´ÓNumsÖвéѯһ°ÙÍòÐУ¬²¢Ê¹ÓÃÒ»¸ön¼Ó1µÄÄÚÁª±í´ïʽ¡£
SELECT n, n+1 AS n2 FROM dbo.Nums WHERE n <= 1000000;
µÚÒ»´ÎÖ´ÐдúÂëʱ¿ÉÄÜҪɨÃèÎïÀíÊý¾Ý¡£Êý¾Ý±»¼ÓÔØµ½»º´æºó£¬ÔÙ´ÎÔËÐиòéѯ²¢Í³¼ÆÔËÐÐʱ¼ä¡£ÔÚÎÒµÄϵͳÉÏÔËÐиôúÂëʱ£¬Ëü²»µ½Ò»ÃëÖÓ¾ÍÍê³ÉÁË¡£
½ÓÏÂÀ´´´½¨fn_add1 UDF£º
IF OBJECT_ID('dbo.fn_add1') IS NOT NULL
DROP FUNCTION dbo.fn_add1;
GO
CREATE FUNCTION dbo.fn_add1(@i AS INT) RETURNS INT
AS
BEGIN
RETURN @i + 1;
END
GO
ʹÓÃfn_add1ÔËÐиòéѯ£º
SELECT n, dbo.fn_add1(n) AS n2 FROM dbo.Nums WHERE n <= 1000000;
²éѯºÄʱ3ÃëÖÓ¡£
ºóÃæÕâ¸ö²éѯµÄ¸ß³É±¾Óëÿ´Îº¯Êýµ÷ÓõĿªÏúÓйء£Äã¿ÉÒÔÔÚÖ´ÐвéѯʱÔËÐÐSQL Server ProfilerÀ´¸ú×ÙSP:Completed£¨»ò SP:Starting£©Ê¼þ£¬ÒÔ¹Û²ì¶ÔUDFµÄ¶à´Îµ÷Óá£
ΪÏÞÖÆ¸ú×ٵĴóС£¬Äã¿ÉÒÔÖ»²âÊÔ¼¸ÐС£ÀýÈ磬ʹÓÃɸѡÆ÷n<=10¡£Í¼6-1ÏÔʾÁËÎÒÔÚ¸ú×Ù²éѯʱµÃµ½µÄʼþ¡£

ͼ6-1 Profiler¸ú×Ù¶Ô±êÁ¿UDFµÄ¶à´Îµ÷ÓÃ
Õâʱ£¬¹Ø±ÕSSMSÖеÄÖ´Ðкó·ÅÆú½á¹ûÑ¡Ïî¡£
ÔÚ´úÂë¼òµ¥ÐÔºÍά»¤ÐÔ·½Ã棬ʹÓÃUDFÓÐÖî¶àºÃ´¦£¬²»¹ýÔÚÐÔÄÜ·½Ã棬Èç¹ûÄãÉè·¨ÔÚ²éѯÖÐʹÓÃÄÚÁª±í´ïʽʵÏÖ¼ÆËã²¢±ÜÃâʹÓÃUDF£¬Í¨³£»á¸üºÃЩ¡£ÓÐʱ£¬Ò»Ð©¿´ÆðÀ´ÐèҪѻ·»ò¹ý³ÌÂß¼µÄ¼ÆËã¾ÓȻҲ¿ÉÒÔʹÓÃÄÚÁª±í´ïʽʵÏÖ£¬ÄãÒ²Ðí»á¶Ô´Ë¸Ðµ½ºÜ³Ô¾ª¡£
ÀýÈ磬ÏÂÃæµÄ²éѯͳ¼Æ±äÁ¿ @findÖеÄ×Ö·û´®ÔÚCustomers. CompanyNameÁÐÖгöÏֵĴÎÊý¡£
DECLARE @find AS NVARCHAR(40);
SET @find = N'n';
SELECT CompanyName,
(LEN(CompanyName+'*') - LEN(REPLACE(CompanyName, @find, '')+'*'))
/ LEN(@find) AS Cnt
FROM dbo.Customers;
±í6-2 ÒÔ¼ò»¯ÐÎʽÏÔʾÁ˲éѯËùÉú³ÉµÄ½á¹û
|
CompanyName |
Cnt |
|
Alfreds Futterkiste |
0 |
|
Ana Trujillo Emparedados y helados |
1 |
|
Antonio Moreno Taquer¨ªa |
3 |
|
Around the Horn |
2 |
|
Berglunds snabbköp |
2 |
Ðø±í
|
CompanyName |
Cnt |
|
Blauer Saee Delikatessen |
1 |
|
Blondesddsl p¨¨re et fils |
1 |
|
B¨®lido Comidas preparadas |
0 |
|
Bon app' |
1 |
|
Bottom-Dollar Markets |
0 |
|
¡ |
¡ |
¸Ã±í´ïʽʹÓÃREPLACEº¯Êý¼ÆËãºÏ¼ÆÊý¡£ËüµÄÂß¼ÊÇÕâÑùµÄ£¬ÏȰÑ×Ö·û´®ÖеÄËùÓÐ @find¶¼É¾³ý£¨Ò²¾ÍÊÇÓᮡ¯Ìæ»»µô£©£¬È»ºó¼ì²éµÃµ½µÄ×Ö·û´®±ÈÔÀ´¶Ì¶àÉÙ£¬ÕâÑù¾Í¿ÉÒÔ¼ÆËã³ö @findÔÚ×Ö·û´®ÖгöÏֵĴÎÊý¡£ÐèҪעÒâµÄÊÇ£¬ÔÚ¼ÆËãËüÃǵij¤¶ÈʱΪÿ¸ö×Ö·û´®Ìí¼ÓÒ»¸ö¡°*¡±ÒÔ±ÜÃâµ±×Ö·û´®°üº¬Î²Ëæ¿Õ¸ñʱµÃµ½´íÎóµÄ³¤¶È¡£
ÔÚÔ¼ÊøÖÐʹÓÃUDF
±êÁ¿UDF¿ÉÒÔÓÃÓÚÔ¼Êø¡£ÕâÒ»½Ú½«ÌÖÂÛ²¢ÑÝʾÈçºÎÔÚDEFAULT¡¢CHECK¡¢PRIMARY KEYºÍUNIQUEÔ¼ÊøÖÐʹÓÃUDF¡£
DEFAULTÔ¼Êø
±êÁ¿UDF¿ÉÒÔÓÃÔÚDEFAULTÔ¼ÊøÖУ¬µ«ËüÓÐÒ»¸öÏÞÖÆ£¬µ±UDFÓÃÓÚDEFAULTÔ¼ÊøÊ±²»ÄܽÓÊոñíµÄÁÐ×÷ΪÊäÈë²ÎÊý¡£´úÂëÇåµ¥6-1ÖеĴúÂë´´½¨±íT1ºÍÃûΪfn_T1_getkeyµÄUDF£¬Ëü·µ»ØT1ÖÐȱÉÙµÄ×îС¼üÖµ¡£
´úÂëÇåµ¥6-1 ´´½¨±íT1 ºÍ fn_T1_getkey UDF
IF OBJECT_ID('dbo.T1') IS NOT NULL
DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1
(
keycol INT NOT NULL CONSTRAINT PK_T1 PRIMARY KEY CHECK (keycol > 0),
datacol VARCHAR(10) NOT NULL
);
GO
IF OBJECT_ID('dbo.fn_T1_getkey') IS NOT NULL
DROP FUNCTION dbo.fn_T1_getkey;
GO
CREATE FUNCTION dbo.fn_T1_getkey() RETURNS INT
AS
BEGIN
RETURN
CASE
WHEN NOT EXISTS(SELECT * FROM dbo.T1 WHERE keycol = 1) THEN 1 ELSE (SELECT MIN(keycol + 1)
FROM dbo.T1 AS A
WHERE NOT EXISTS
(SELECT *
FROM dbo.T1 AS B
WHERE B.keycol = A.keycol + 1))
END;
END
GO
ÏÂÃæµÄ´úÂëÏòkeycolÁÐÌí¼ÓÒ»¸öDEFAULTÔ¼Êø£¬¸ÃÔ¼Êøµ÷ÓÃfn_T1_getkeyº¯Êý£º
ALTER TABLE dbo.T1 ADD DEFAULT£¨dbo.fn_T1_getkey()£© FOR keycol;
×¢Òâ Õâ¸öDEFAULTÔ¼ÊøÖ»ÔÚ²åÈëµ¥ÐÐʱִÐУ¬²åÈë¶àÐÐʱ²»»áÖ´ÐС£ÔÚʵ¼ÊµÄÒµÎñ·½°¸ÖÐÖØÓüüÖµ·Ç³£²»Ã÷ÖÇ¡£ÎÒʹÓÃÕâ¸öÀý×ÓÖ»ÊÇΪÁËÑÝʾ¶øÒÑ¡£
ÏÂÃæµÄ´úÂëÏÈÏò±íÖвåÈëÈýÐУ¬Éú³ÉµÄ¼üֵΪ1¡¢2¡¢3£¬È»ºóɾ³ý¼üֵΪ2µÄÐУ¬ÔÙ²åÈëÒ»¸öÐÂÐУ¬²¢Éú³É¼üÖµ2
INSERT INTO dbo.T1(datacol) VALUES('a');
INSERT INTO dbo.T1(datacol) VALUES('b');
INSERT INTO dbo.T1(datacol) VALUES('c');
DELETE FROM dbo.T1 WHERE keycol = 2;
INSERT INTO dbo.T1(datacol) VALUES('d');
ʹÓÃÏÂÃæµÄ´úÂë²éѯ¸Ã±í£¬Èç±í6-3Ëùʾ£¬¼üÖµ2±»¸³¸ø×îºó²åÈëµÄÐÐ(datacol=¡®d¡¯)£¬ÒòΪ¼üֵΪ2µÄÐÐ֮ǰ±»É¾³ý£º
SELECT * FROM dbo.T1;
±í6-3 T1 µÄÄÚÈÝ
|
Keycol |
datacol |
|
1 |
a |
|
2 |
d |
|
3 |
C |
CHECKÔ¼Êø
²»Í¬ÓÚÔÚDEFAULTÔ¼ÊøÖÐʹÓõÄUDF£¬ÔÚCHECKÔ¼ÊøÖÐʹÓÃUDFʱ¿ÉÒÔÒýÓñíÖеÄÁÐ×÷ΪÊäÈë¡£ÔÚCHECKÔ¼ÊøÖÐʹÓÃUDF¿ÉÒÔʵÏÖ¹¦ÄÜÇ¿´óµÄÇ¿ÖÆÍêÕûÐÔ¹æÔò£¨integrity rule£©£¬ÕâÑùÄã¾Í¿ÉÒÔÔÚijЩÇé¿öϱÜÃâʹÓÃͨ³£³É±¾¸ü¸ßµÄ´¥·¢Æ÷¡£ÔÚ±¾ÕµĺóÃæ£¬ÎÒ½«ÑÝʾÈçºÎÔÚCHECKÔ¼ÊøÖÐʹÓÃUDF£¬Ê¾ÀýÖеÄUDF»ùÓÚÕýÔò±í´ïʽƥÅäÊäÈëµÄ×Ö·û´®¡£
PRIMARY KEY ºÍ UNIQUE Ô¼Êø
Äã¿ÉÒÔÔÚµ÷ÓÃUDFµÄ¼ÆËãÁÐÉÏ´´½¨UNIQUE »ò PRIMARY KEYÔ¼Êø¡£ÕâÁ½¸öÔ¼Êø»áÔÚºǫ́´´½¨Î¨Ò»Ë÷Òý¡£ÕâÒâζ×ÅÄ¿±ê¼ÆËãÁкÍËüµ÷ÓõÄUDF±ØÐëÂú×ãË÷Òý×¼Ôò£¨indexing guideline£©¡£ÀýÈ磬UDF±ØÐë°ó¶¨µ½¼Ü¹¹£¨Ê¹ÓÃSCHEMABINDINGÑ¡Ïî´´½¨£©£¬¼ÆËãÁбØÐë¾ßÓÐÈ·¶¨ÐÔÇÒÊǾ«È·µÄ£¬»òÕß¾ßÓÐÈ·¶¨ÐÔÇÒÊdz־õģ¬µÈµÈ¡£Äã¿ÉÒÔÔÚÁª»ú´ÔÊéÖÐÕÒµ½¹ØÓÚ¼ÆËãÁкÍUDFË÷Òý×¼ÔòµÄ¸üÏêϸÐÅÏ¢¡£
ÏÂÃæµÄ´úÂë³¢ÊÔÏòT1ÖÐÌí¼ÓÒ»¸öµ÷ÓÃfn_add1 UDFµÄ¼ÆËãÁÐcol1£¬²¢ÔÚ¸ÃÁÐÉÏ´´½¨Ò»¸öUNIQUEÔ¼Êø¡£
ALTER TABLE dbo.T1
ADD col1 AS dbo.fn_add1(keycol) CONSTRAINT UQ_T1_col1 UNIQUE;
¸Ã²Ù×÷½«Ê§°Ü²¢·µ»ØÏÂÃæµÄ´íÎó£º
Msg 2729, Level 16, State 1, Line 1
Column 'col1' in table 'dbo.T1' cannot be used in an index or statistics or as a partition
key because it is non-deterministic.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
²úÉú¸Ã´íÎóµÄÔÒòÊǸú¯Êý²»Âú×ã´´½¨Ë÷ÒýµÄ±ØÒªÌõ¼þÖ®Ò»£¬¼´º¯Êý±ØÐë°ó¶¨µ½¼Ü¹¹¡£ÈçÄãËù¼û£¬¸Ã´íÎóÏûÏ¢±¾Éí²¢Î´Ö¸³ö¸Ã´íÎó²úÉúµÄÔÒò»ò½¨ÒéÄãÈçºÎ±ÜÃâ¸Ã´íÎó¡£Òª½â¾ö¸ÃÎÊÌ⣬ÄãÓ¦¸ÃΪ¸Ãº¯ÊýÔö¼ÓSCHEMABINDINGÑ¡Ïî¡£
ALTER FUNCTION dbo.fn_add1(@i AS INT) RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
RETURN @i + 1;
END
GO
Ôٴγ¢ÊÔÌí¼Ó°üº¬UNIQUEÔ¼ÊøµÄ¼ÆËãÁУ¬ÕâÒ»´Î´úÂë¿ÉÒÔÕýÈ·ÔËÐС£
ALTER TABLE dbo.T1
ADD col1 AS dbo.fn_add1(keycol) CONSTRAINT UQ_T1_col1 UNIQUE;
ÒªÔÚÕâÑùµÄ¼ÆËãÁÐÉÏ´´½¨PRIMARY KEYÔ¼ÊøÐèÒªÒ»µã¼¼ÇÉ¡£ÎÒÃÇÀ´¿´ÈçºÎʵÏÖ£¬ÏÈ´ÓT1ÖÐɾ³ýÒÑ´æÔÚµÄPRIMARY KEY¡£
ALTER TABLE dbo.T1 DROP CONSTRAINT PK_T1;
È»ºó³¢ÊÔÌí¼ÓÁíÒ»¸ö°üº¬PRIMARY KEYÔ¼ÊøµÄ¼ÆËãÁÐcol2¡£
ALTER TABLE dbo.T1
ADD col2 AS dbo.fn_add1(keycol)
CONSTRAINT PK_T1 PRIMARY KEY;
¸Ã³¢ÊÔ½«Ê§°Ü£¬²¢²úÉúÏÂÃæµÄ´íÎó£º
Msg 1711, Level 16, State 1, Line 1
Cannot define PRIMARY KEY constraint on column 'col2' in table 'T1'. The computed column has to be persisted and not nullable.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.
Äã±ØÐëÃ÷È·±£Ö¤col2ÓÀÔ¶²»»á³öÏÖNULLÖµ¡£Îª´Ë£¬Äã¿ÉÒÔ°ÑÁж¨ÒåΪPERSISTED ºÍ NOT NULL£¬¾ÍÏñÕâÑù£º
ALTER TABLE dbo.T1
ADD col2 AS dbo.fn_add1(keycol) PERSISTED NOT NULL
CONSTRAINT PK_T1 PRIMARY KEY;
PERSISTEDÑ¡ÏîÊÇSQL Server 2005ÖÐÐÂÔöµÄ¡£ÔÚSQL Server 2000ÖУ¬ÒªÔÚ¼ÆËãÁÐÉÏ´´½¨Ö÷¼üÔ¼Êø£¬Äã±ØÐëÓÃISNULLº¯Êý·â×°¶ÔUDFµÄµ÷Ó㬾ÍÏñÕâÑù£º
ALTER TABLE dbo.T1
ADD col2 AS ISNULL(dbo.fn_add1(keycol), 0)
CONSTRAINT PK_T1 PRIMARY KEY;
Íê³Éºó£¬ÔËÐÐÏÂÃæµÄ´úÂë½øÐÐÇåÀí¡£
IF OBJECT_ID('dbo.T1') IS NOT NULL
DROP TABLE dbo.T1;
GO
IF OBJECT_ID('dbo.fn_T1_getkey') IS NOT NULL
DROP FUNCTION dbo.fn_T1_getkey;
GO
IF OBJECT_ID('dbo.fn_T1_datacol_count') IS NOT NULL
DROP FUNCTION dbo.fn_T1_datacol_count;
CLR ±êÁ¿ UDF
ÕâÒ»½Ú½éÉÜCLR±êÁ¿UDF²¢±È½ÏËüºÍT-SQL UDFÖ®¼äµÄ¹ØÏµ¡£¸½Â¼AÖÐÌṩÁËÄãÔÚ¿ª·¢¡¢Éú³É¡¢²¿ÊðºÍ²âÊÔCLR³ÌÐòʱӦ¸Ã×ñѵIJÙ×÷Ö¸ÄÏ¡£ÔÚ±¾ÕÂÒÔ¼°ÆäËûÃèÊöCLR³ÌÐòµÄÕ½ÚÖУ¬ÎÒ½«Ö»¹Ø×¢³ÌÐò´úÂë±¾Éí¡£¸½Â¼ÖÐÌṩÁËÃüÃû¿Õ¼ä¶¨ÒåºÍCLRUtilitiesÀà¡£ÏÂÃæÊÇC# °æµÄÃüÃû¿Õ¼ä¶¨ÒåºÍCLRUtilitiesÀàµÄ¿ªÊ¼²¿·Ö¡£
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
public partial class CLRUtilities
{
... ÕâÀïÊdzÌÐò¶¨Òå ...
}
ÏÂÃæÊÇVisual Basic°æ±¾µÄ´úÂ룺
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Collections
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Reflection
Imports System.Runtime.InteropServices
Partial Public Class CLRUtilities
... ÕâÀïÊdzÌÐò¶¨Òå...
End Class
ÎÒ²»»áÔÚÕâÀïÖØ¸´ÃüÃû¿Õ¼äºÍÀàµÄ¶¨Òå¡£Ò²²»»áÌṩËùÉæ¼°µÄͨÓò½Ö裬ÕâЩÔÚ¸½Â¼ÖÐÒѾ·Ç³£ÏêϸÁË¡£
CLR³ÌÐò
ÔÚSQL ServerÖпª·¢CLR³ÌÐòµÄÄÜÁ¦¸øÄãÌṩÁËÇ¿´óµÄ¹¦ÄÜ£¬µ«Í¬Ê±ËüÒ²´øÀ´Á˼«´óµÄ·çÏÕ¡£ .NET°üº¬Á˷ḻµÄ¿ª·¢¼¼ÊõÒÔ¼°ÔÚijЩÁìÓò±ÈT-SQL¸ü¸ßµÄÐÔÄÜ£¬T-SQLÓÀÔ¶²»»á±»Éè¼ÆÓÃÓÚ¸ßЧµØ´¦ÀíÕâЩÁìÓò¡£ÕâЩÁìÓò°üÀ¨¸´ÔÓ¼ÆËã¡¢±éÀúºÍ¹ý³ÌÂß¼¡¢×Ö·û´®´¦Àí¡¢¶Ô²Ù×÷ϵͳ×ÊÔ´µÄÍⲿ·ÃÎʵȵȡ£T-SQLÊÇÒ»ÖÖÉùÃ÷ʽÓïÑÔ£¨declarative language£©¡£µ±Ê¹ÓûùÓÚ¼¯ºÏµÄ²éѯ½øÐÐÊý¾Ý²Ù×÷ʱ£¬Ëü±È .NETÓµÓиüÇ¿´óµÄ¹¦Äܺ͸ü¸ßµÄÐÔÄÜ¡£¼¯³É .NETµÄΣÏÕÔÚÓÚ£¬¶ÔÓÚÄÇЩ»¹Î´¾ß±¸SQL˼ά·½Ê½µÄ¿ª·¢ÈËÔ±À´ËµËüÒ²ÊÇÒ»¸öý½é£¬»áµ¼ÖÂËûÃÇ¿ª·¢³öÐÔÄÜÔã¸âµÄ´úÂë¡£ÔÚ±¾ÊéÖУ¬ÎÒ½«ÌṩһЩӦ¸ÃʹÓà .NET¿ª·¢µÄʾÀý¡£
¸ü¶àÐÅÏ¢ ¹ØÓÚ»ùÓÚ¼¯ºÏµÄ²éѯºÍ¸ßЧµÄ»ùÓÚ¼¯ºÏ½â¾ö·½°¸µÄÐÅÏ¢£¬Çë²Î¿¼Inside T-SQL QueryingÒ»Ê飬¸ÃÊé¸üΪÉîÈëµÄ½éÉÜÁËÕâЩÖ÷Ìâ¡£
ÕýÔò±í´ïʽ
ÕýÔò±í´ïʽΪÄãÌṩÁËÒ»ÖÖ¹¦ÄÜÇ¿´óµÄ·½·¨£¬¿ÉÒÔÀûÓÃһЩ¼òÃ÷Áé»îµÄ·ûºÅÆ¥ÅäÎı¾µÄģʽ£¨patterns of text£©¡£ANSI SQL¶¨ÒåÁËSIMILAR TOν´ÊÒÔÖ§³ÖÕýÔò±í´ïʽ£¬²»ÐÒµÄÊÇ£¬SQL Server 2005²¢Î´ÔÚT-SQLÖÐʵÏÖ¸Ãν´Ê¡£µ«Äã¿ÉÀûÓà .NET´úÂëÖеÄÕýÔò±í´ïʽ¡£ÀýÈ磬ÏÂÃæµÄC# ´úÂ붨ÒåÁËÒ»¸öÃûΪfn_RegExMatchµÄº¯Êý¡£
// ʹÓÃÕýÔò±í´ïʽÑéÖ¤ÊäÈëµÄ×Ö·û´®
[SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
public static SqlBoolean fn_RegExMatch(SqlString inpStr,
SqlString regExStr)
{
if (inpStr.IsNull || regExStr.IsNull)
return SqlBoolean.Null;
else
return (SqlBoolean)Regex.IsMatch(inpStr.Value, regExStr.Value ,
RegexOptions.CultureInvariant);
}
·½·¨Í·ÖеÄÊôÐÔ֪ͨSQL Server¸Ã·½·¨¾ßÓÐÈ·¶¨ÐÔ²¢ÇÒ²»Éæ¼°Êý¾Ý·ÃÎÊ¡£×¢Òâ´úÂëʹÓÃÁËRegexOptions.CultureInvariantÑ¡ÏîÒÔ»ñµÃÎÄ»¯ÖÐÁ¢£¨culture-independent£©µÄÆ¥Åä½á¹û¡£Èç¹ûÆ¥ÅäÊÇÎÄ»¯ÒÀÀµ£¨culture-dependent£©µÄ£¬¸Ã·½·¨½«²»¾ßÓÐÈ·¶¨ÐÔ¡££¨ÏêÇéÇë²Î¼ûhttp://msdn2.microsoft.com/en-us/library/z0sbec17.aspx£©¡£
¸Ãº¯Êý½ÓÊÕÒ»¸ö×Ö·û´®£¨inpStr£©ºÍÒ»¸öÕýÔò±í´ïʽ£¨regExStr£©×÷ΪÊäÈë¡£º¯ÊýµÄ·µ»ØÀàÐÍÊÇSqlBoolean£¬ËüÓÐÈýÖÖ¿ÉÄܵÄÖµ£º0¡¢1ºÍNull¡£Èç¹ûregExStr»òinpStrÊÇNullÔò·µ»ØÖµÎªNull£¬Èç¹ûÔÚinpStrÖÐÕÒµ½regExStrģʽÔò·µ»Ø1£¬Ôò·ñ·µ»Ø0¡£ÈçÄãËù¼û£¬¸Ãº¯ÊýµÄ´úÂë·Ç³£¼òµ¥¡£´úÂëÊ×ÏȲâÊÔÊäÈë²ÎÊýÊÇ·ñΪNULL£¬Èç¹ûÓÐÒ»¸öÊÇNULLÔò·µ»ØNULL¡£Èç¹ûÊäÈë²ÎÊý¶¼²»ÎªNULL£¬Ôòº¯Êý·µ»ØRegEx.IsMatch·½·¨µÄ½á¹û¡£Õâ¸ö·½·¨¼ì²éµÚÒ»¸ö²ÎÊýËùÌṩµÄ×Ö·û´®ÊÇ·ñ°üº¬µÚ¶þ¸ö²ÎÊýÖÐÌṩµÄģʽ¡£RegEx.IsMatch·½·¨·µ»Ø .NETµÄSystem.BooleanÖµ£¬¸ÃÖµ±ØÐëÏÔʽת»»ÎªSqlBoolean¡£
Ò²ÐíÄã¸üϲ»¶Ê¹ÓÃVisual Basic£¬ÏÂÃæ¾ÍÊÇʹÓÃVisual BasicʵÏֵĺ¯Êý´úÂë¡£
' ʹÓÃÕýÔò±í´ïʽÑéÖ¤ÊäÈëµÄ×Ö·û´®
<SqlFunction(IsDeterministic:=True, DataAccess:=DataAccessKind.None)> _
Public Shared Function fn_RegExMatch(ByVal inpStr As SqlString, _
ByVal regExStr As SqlString) As SqlBoolean
If (inpStr.IsNull Or regExStr.IsNull) Then
Return SqlBoolean.Null
Else
Return CType(Regex.IsMatch(inpStr.Value, regExStr.Value, _
RegexOptions.CultureInvariant), SqlBoolean)
End If
End Function
Èç¹ûÄã×ñÑÁ˸½Â¼AÖÐÃèÊöµÄÖ¸µ¼£¬ÄÇôÄãÒѾ×÷ºÃÁ˲âÊÔºÍʹÓøú¯ÊýµÄ×¼±¸ÁË¡£ÕâЩָµ¼°üº¬£ºÔÚSQL ServerÖ줻îCLR£¨Ä¬ÈÏÊǽûÓõģ©¡¢´´½¨ÃûΪCLRUtilitiesµÄ²âÊÔÊý¾Ý¿â£¬ÔÚMicrosoft Visual Studio 2005Öпª·¢´úÂ룬ÔÚ´ÅÅÌÉÏÉú³É .dll³ÌÐò¼¯¡¢´Ó³ÌÐò¼¯ÖаÑIntermediate Language£¨IL£©´úÂë¼ÓÔØµ½SQL ServerÊý¾Ý¿â£¬²¢ÔÚÊý¾Ý¿âÖÐ×¢²á³ÌÐò¼¯ÖеijÌÐò¡£ÔËÐÐÏÂÃæµÄ´úÂëÀ´¼¤»îSQL ServerÖеÄCLR²¢´´½¨CLRUtilities²âÊÔÊý¾Ý¿â¡£
SET NOCOUNT ON;
USE master;
EXEC sp_configure 'clr enabled', 1;
RECONFIGURE;
GO
IF DB_ID('CLRUtilities') IS NOT NULL
DROP DATABASE CLRUtilities;
GO
CREATE DATABASE CLRUtilities;
GO
USE CLRUtilities;
GO
×¢Òâ ¿ªÆô'clr enabled'·þÎñÅäÖÃÑ¡ÏĬÈÏÊǽûÓõģ©ºó£¬¾Í±íʾMicrosoft SQL Server¿ÉÒÔÔÚʵÀý¼¶±ðÉÏÔËÐÐÓû§ºÍÐò¼¯¡£Äã²»ÄÜÔÚ¸üϸµÄÁ£¶È¼¶±ðÉÏ¿ØÖƸÃÑ¡ÏËùÒÔ£¬¼¤»î¸ÃÑ¡ÏÄã¾ÍΪÕû¸öSQL ServerʵÀýÉϼ¤»îÁ˸ÃÑ¡Ïî¡£¼¤»î¸ÃÑ¡Ïî¿ÉÄܻᵼÖ°²È«·çÏÕ¡£·çÏյļ¶±ðÈ¡¾öÓÚÄãÔÊÐíÿ¸ö³ÌÐòÖ´ÐÐʲô²Ù×÷¡£µ±Ê¹ÓÃCREATE ASSEMBLYÃüÁî´´½¨³ÌÐò¼¯Ê±£¬Í¨¹ý°ÑPERMISSION_SETÑ¡ÏîÉèÖÃΪSAFE¡¢
EXTERNAL_ACCESS »ò
UNSAFE¿ÉÒÔ¿ØÖÆ´úÂëµÄ·ÃÎÊȨÏÞ¡£ÏÂÃæÊÇÁª»ú´ÔÊéÃèÊöÕâÈý¸öÑ¡ÏîʱµÄ°²È«ËµÃ÷£º
¶ÔÓÚÖ´ÐмÆËãºÍÊý¾Ý¹ÜÀíÈÎÎñ¶øÎÞÐè·ÃÎÊ
SQL Server ʵÀýÍⲿ×ÊÔ´µÄ³ÌÐò¼¯£¬SAFE ÊÇÍÆ¼öµÄȨÏÞ¼¯¡£
¶ÔÓÚ·ÃÎÊ SQL Server ʵÀýÍⲿ×ÊÔ´µÄ³ÌÐò¼¯£¬ÎÒÃÇÍÆ¼öʹÓà EXTERNAL_ACCESS¡£EXTERNAL_ACCESS ³ÌÐò¼¯°üº¬ SAFE ³ÌÐò¼¯µÄ¿É¿¿ÐԺͿÉÉìËõÐÔ±£»¤£¬µ«´Ó°²È«½Ç¶È¶øÑÔ£¬ËüÓë UNSAFE ³ÌÐò¼¯ÀàËÆ¡£ÔÒòÊÇÔÚĬÈÏÇé¿öÏ£¬EXTERNAL_ACCESS ³ÌÐò¼¯ÖеĴúÂëÒÔ SQL Server ·þÎñÕË»§Éí·ÝÔËÐв¢·ÃÎÊ´ËÕË»§µÄÍⲿ×ÊÔ´£¬³ý·Ç´Ë´úÂëÏÔʽģÄâµ÷Ó÷½¡£Òò´Ë£¬´´½¨ EXTERNAL_ACCESS ³ÌÐò¼¯µÄȨÏÞÓ¦Ö»ÊÚÓèÒÔ SQL Server ·þÎñÕË»§Éí·ÝÔËÐдúÂëµÄ¿ÉÐŵǼ¡£ÓйØÄ£ÄâµÄÏêϸÐÅÏ¢£¬Çë²ÎÔÄ CLR Integration Security¡£
Ö¸¶¨ UNSAFE ½«Ê¹³ÌÐò¼¯µÄ´úÂëÔÚ SQL Server ½ø³Ì¿Õ¼äÖÐÖ´ÐÐÈÎÒâ²Ù×÷£¬ÕâЩ²Ù×÷ÓпÉÄÜÆÆ»µSQL ServerµÄ½¡×³ÐÔ¡£UNSAFE ³ÌÐò¼¯»¹¿ÉÄÜ»áÆÆ»µ SQL Server »òCommon Language RuntimeµÄ°²È«ÏµÍ³¡£UNSAFE ȨÏÞÖ»Ó¦ÊÚÓè¸ß¶È¿ÉÐŵijÌÐò¼¯¡£Ö»ÓÐ sysadmin ¹Ì¶¨·þÎñÆ÷½ÇÉ«µÄ³ÉÔ±²ÅÄÜ´´½¨²¢ÐÞ¸ÄUNSAFE ³ÌÐò¼¯¡£
±¾ÕÂËùÌÖÂ۵ĺ¯Êý¶¼²»ÐèÒª·ÃÎÊÍⲿ×ÊÔ´£¬ËùÒÔ´´½¨³ÌÐò¼¯Ê±½«Ê¹ÓÃSAFEȨÏÞ¼¯£¨permission set£©¡£ÔÚÏÂÒ»ÕÂÖУ¬ÎÒ½«ÑÝʾһ¸öÐèÒªEXTERNAL_ACCESSȨÏÞ¼¯µÄ´æ´¢¹ý³ÌºÍÒ»¸öÐèÒªUNSAFEȨÏÞ¼¯µÄ´¥·¢Æ÷£¬µ«Ö»ÊdzöÓÚÑÝʾĿµÄ¡£ÑÝʾÕâЩ³ÌÐòʱ£¬ÎÒ½«Ð޸ĸóÌÐò¼¯ÒÔÖ§³ÖËùÐèÒªµÄȨÏÞ¼¯¡£ÔÊÐí³ÌÐò¼¯½øÐÐÍⲿ·ÃÎÊ»á´øÀ´°²È«·çÏÕ£¬ÀμÇÕâÒ»µã¡£
ÔÚºóÃæµÄËùÓеÄʾÀýÖУ¬ÎÒ¶¼¼ÙÉèÒÑ´æÔÚCLRUtilitiesÊý¾Ý¿â²¢ÇÒÒѾʹÓÃVisual StudioÉú³É³ÌÐò¼¯¡£Èç¹ûÄ㻹ûÓаѳÌÐò¼¯¼ÓÔØµ½Êý¾Ý¿â£¬ÔËÐÐÏÂÃæµÄ´úÂëÍê³É¸Ã²Ù×÷¡£
USE CLRUtilities;
GO
CREATE ASSEMBLY CLRUtilities
FROM 'C:\CLRUtilities\CLRUtilities\bin\Debug\CLRUtilities.dll'
WITH PERMISSION_SET = SAFE;
-- Èç¹ûûÓÐDebug Îļþ¼Ð£¬ÔòʹÓÃÕâ¸öµØÖ·:
-- FROM 'C:\CLRUtilities\CLRUtilities\bin\CLRUtilities.dll'
µ±È»£¬Èç¹û°üº¬³ÌÐò¼¯µÄCLRUtilities.dllÎļþλÓÚÁíÒ»¸öÎļþ¼Ð£¬ÔòÌæ»»ÎªËüËùÔÚµÄÎļþ¼Ð¡£CREATE ASSEMBLY ÃüÁî°ÑIL´úÂë´Ó .dllÎļþ¼ÓÔØµ½Êý¾Ý¿â¡£Ò»µ©¼ÓÔØ£¬Äã¾Í²»ÔÙÐèÒªÍⲿÎļþÁË¡£Òª×¢ÒâµÄÊÇ£¬Èç¹ûÄãÌí¼Ó³ÌÐòºóÖØÐÂÉú³ÉÁ˳ÌÐò¼¯£¬¶øÇÒÔÚVisual Studio Professional°æÖÐδѡÔñ×Ô¶¯²¿ÊðÑ¡ÏÄãÐèÒªÖ´ÐÐALTER ASSEMBLY »ò DROP ºÍCREATE ASSEMBLYÃüÁÊÖ¹¤°ÑIL´úÂëÖØÐ¼ÓÔØµ½Êý¾Ý¿â¡£Èç¹ûÄã×ñÑÁ˸½Â¼AÖеÄÖ¸µ¼¶øÇÒÒѾ´´½¨Á˱¾ÊéÖÐÌÖÂÛµÄËùÓгÌÐò£¬¿ÉÒÔÊ¡ÂÔÕâÒ»²½Öè¡£ÒÔºóÎÒ²»ÔÙÌá¼°ÕâÒ»²½¡£
ÔÚÌÖÂÛеijÌÐòʱ£¬ÎÒ»áÌṩÔÚÊý¾Ý¿â×¢²áËüÃÇËùÐèµÄT-SQL´úÂ루CREATE FUNCTION | PROCEDURE | TRIGGERÃüÁ£¬¾¡¹ÜÈç¹ûÄãÍêÈ«×ñѸ½Â¼AÖеÄÖ¸µ¼£¬Êµ¼ÊÉϲ¢²»ÐèÒªÔËÐÐÕâЩ´úÂë¡£
ÏÂÃæÊÇÄãÐèÒªÔÚCLRUtilitiesÊý¾Ý¿âÖÐ×¢²áC# °æfn_RegExMatchËùÐèµÄ´úÂë¡£
USE CLRUtilities;
GO
IF OBJECT_ID('dbo.fn_RegExMatch') IS NOT NULL
DROP FUNCTION dbo.fn_RegExMatch;
GO
CREATE FUNCTION dbo.fn_RegExMatch
(@inpstr AS NVARCHAR(MAX), @regexstr AS NVARCHAR(MAX))
RETURNS BIT
EXTERNAL NAME CLRUtilities.CLRUtilities.fn_RegExMatch;
ÏÂÃæÊÇ×¢²á Visual Basic°æfn_RegExMatchµÄ´úÂë¡£
CREATE FUNCTION dbo.fn_RegExMatch
(@inpstr AS NVARCHAR(MAX), @regexstr AS NVARCHAR(MAX))
RETURNS BIT
EXTERNAL NAME CLRUtilities.[CLRUtilities.CLRUtilities].fn_RegExMatch;
×¢Òâ ÔÚ×¢²áC# °æ±¾ºÍVisual Basic°æ±¾µÄº¯Êýʱ£¬ÎªÆäÖ¸¶¨Á˲»Í¬µÄEXTERNALNAME (CLRUtilities
CLRUtilities.fn_RegExMatchºÍCLRUtilities.[CLRUtilities. CLRUtilities].fn_RegExMatch)¡£ÕâÒ»µã·Ç³£ÁíÈËÃÔ»ó¡£ÔÚ֮ǰµÄ .NET°æ±¾ÖÐ(2002,2003)£¬µ±Äã´´½¨ÁËÒ»¸öÀà¿âʱ£¬C# »áÓúÍÀàÏàͬµÄÃû³ÆÌí¼Ó¸ùÃüÃû¿Õ¼ä(root namespace)£¬¶øVisual Basic²»ÊÇÕâÑù¡£Õâ¾Íµ¼ÖÂÁ˲»Í¬µÄ½á¹û£ºVisual Basic´´½¨ÁËÒ»¸ö¸ùÃüÃû¿Õ¼ä£¬¶øC# ²»»á¡£Îª±£Ö¤Ê¹Óò»Í¬ .NETÓïÑÔʱT-SQL´úÂëµÄÒ»ÖÂÐÔ£¬ÔÚʹÓÃVisual Basic±à³Ìʱ±ØÐë±ÜÃâ´´½¨¸ùÃüÃû¿Õ¼ä¡£ÔÚVisual StudioÖУ¬ÓÒ¼üµ¥»÷¸ÃÏîÄ¿£¬Ñ¡ÔñÊôÐÔ¡¢Ó¦ÓóÌÐòÒ³¡£Çå¿Õ¡°¸ùÃüÃû¿Õ¼ä¡±Îı¾¿òµÄÄÚÈÝ¡£ÔÚ±¾ÊéÖУ¬ÎÒ½«¼ÙÉèÄãδÇå¿Õ¸ÃÑ¡ÏÒò´Ë£¬µ±×¢²á¶ÔÏóʱÄã»á¿´µ½Ö¸¶¨µÄÍⲿÃû³ÆµÄ²îÒì¡£
ÕâÑùÄã¾Í¿ÉÒÔʹÓÃfn_RegExMatchº¯ÊýÁË¡£
¸ü¶àÐÅÏ¢ Äã¿ÉÒÔÔÚ»¥ÁªÍøÉÏÕÒµ½¸ü¶àÓÐÓõÄÕýÔò±í´ïʽ¡£ÀýÈ磺http://www.regexlib.
com¡£
×÷Ϊһ¸öʹÓÃÕâ¸öк¯ÊýµÄʾÀý£¬¼ÙÉèÄãÏë¼ì²éÒ»¸öE-mailµØÖ·ÊÇ·ñÓÐЧ£¬Äã¿ÉÒÔʹÓÃÕâ¸öÕýÔò±í´ïʽ£ºN'^([\w-]+\.)*?[\w-]+@[\w-]+\.([\w-]+\.)*?[\w]+$'.
¸ÃÕýÔò±í´ïʽ¼ì²éµØÖ·ÊÇ·ñÒÔÒ»¸öµ¥´ÊΪ¿ªÍ·£¬°üº¬¡°at¡±£¨@£©·ûºÅ£¬¶øÇÒÔÚ@·ûºÅÖ®ºóÖÁÉÙÓÐÁ½¸öµ¥´Ê£¬µ¥´ÊÖ®¼äÓõã(.)·Ö¸ô¡£ÔÚ@·ûºÅµÄÇ°ÃæºÍºóÃæ£¬¿ÉÒÔ°üº¬ÆäËûһЩÒÔµã·Ö¸ôµÄµ¥´Ê¡£Õâ¸öÕýÔò±í´ïʽ·Ç³£¼òµ¥£¬Ìṩ¸ÃÕýÔò±í´ïʽֻÊÇΪÁËÑÝʾ£¬ÒªÑ§Ï°ÈçºÎ±àд¸ü½¡×³¸üÍêÕûµÄÕýÔò±í´ïʽ£¬½¨ÒéÄã·ÃÎÊhttp://www.regularexpressions.info/¡£
ÏÂÃæµÄ´úÂë·µ»Ø1£¬ÒòΪËüËùÌṩµÄE-mailµØÖ·ÊÇÓÐЧµÄ¡£
SELECT dbo.fn_RegExMatch(
N'dejan@solidqualitylearning.com',
N'^([\w-]+\.)*?[\w-]+@[\w-]+\.([\w-]+\.)*?[\w]+$');
¶øÏÂÃæµÄ´úÂ뽫·µ»Ø0£¬ÒòΪ¸ÃµØÖ·ÎÞЧ¡£
SELECT dbo.fn_RegExMatch(
N'dejan#solidqualitylearning.com',
N'^([\w-]+\.)*?[\w-]+@[\w-]+\.([\w-]+\.)*?[\w]+$');
Ä㻹¿ÉÒÔÔÚCHECKÔ¼ÊøÖÐʹÓøú¯Êý¡£ÀýÈ磬ÏÂÃæµÄ´úÂë»á´´½¨Ò»¸öʹÓÃCHECKÔ¼ÊøµÄTestRegEx±í£¬¸ÃÔ¼ÊøÏÞÖÆÁËjpgfilenameÁеÄÖµ±ØÐëÊÇÒÔjpgΪÀ©Õ¹ÃûµÄÎļþÃû¡£
IF OBJECT_ID('dbo.TestRegEx') IS NOT NULL
DROP TABLE dbo.TestRegEx;
GO
CREATE TABLE dbo.TestRegEx
(
jpgfilename NVARCHAR(4000) NOT NULL
CHECK(dbo.fn_RegExMatch(jpgfilename,
N'^(([a-zA-Z]:)|(\\{2}\w+)\$?)(\\(\w[\w ]*.*))+\.(jpg|JPG)$')
= CAST(1 As BIT))
);
JpgfilenameÁеÄÖµ±ØÐëÂú×ãÏÂÃæµÄģʽ£ºÒÔÒ»¸öAµ½ZÖ®¼äµÄ×Öĸ¿ªÍ·£¬ºó¸úÒ»¸öðºÅ£¨ÅÌ·û£©£¬»òÕßÊÇÁ½¸ö·´Ð±ÏߺÍÒ»¸öµ¥´Ê£¨ÍøÂç¹²Ïí£©¡£¶øÇÒ¸ÃÖµ±ØÐëÖÁÉÙ°üº¬Ò»¸ö±íʾ´ÅÅÌ»ò¹²ÏíµÄ¸ùĿ¼µÄ·´Ð±Ïß¡£È»ºó£¬¸ÃÖµ¿ÉÒÔÔÙ°üº¬Ò»Ð©±íʾ¶à¸ö×ÓÎļþ¼ÐµÄ·´Ð±Ïß/×Ö·ûµÄ×éºÏ¡£×îºó¼¸¸ö×Ö·û±ØÐëÊÇ¡°. jpg¡±£¨´óд»òСд£©¡£
ÏÂÃæ°üº¬ÓÐЧJPEGÎļþÃûµÄINSERT¿ÉÒÔ±»½ÓÊÜ£º
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'C:\Temp\myFile.jpg');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'\\MyShare\Temp\myFile.jpg');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'\\MyShare\myFile.jpg');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'C:\myFile.jpg');
¶øÏÂÃæ°üº¬ .txtÎļþÃûµÄINSERT»á±»¾Ü¾ø£º
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'C:\Temp\myFile.txt');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'\\MyShare\\Temp\myFile.jpg');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'\\myFile.jpg');
INSERT INTO dbo.TestRegEx(jpgfilename) VALUES(N'C:myFile.jpg');
Íê³Éºó£¬ÔËÐÐÏÂÃæµÄ´úÂë½øÐÐÇåÀí£º
IF OBJECT_ID('dbo.TestRegEx') IS NOT NULL
DROP TABLE dbo.TestRegEx;
GO
IF OBJECT_ID('dbo.fn_RegExMatch') IS NOT NULL
DROP FUNCTION dbo.fn_RegExMatch;
ÏÔʽºÍÒþʽת»»
ÔÚSQL Server 2005Öпª·¢CLR¶ÔÏóʱ£¬Äã¿ÉÒÔʹÓà .NET±¾»úÀàÐÍ£¨native type£©ºÍ .NET SQLÀàÐÍÀ´¶¨ÒåÊäÈë/Êä³ö²ÎÊýºÍ±äÁ¿¡£.NET SQLÀàÐÍÓ³Éäµ½SQL ServerÀàÐÍʱ¸ü¾«È·¡£ÔÚ³ÌÐò½Ó¿ÚÖÐʹÓà .NET±¾»úÀàÐͻᵼÖÂÓëSQL Server»òµ½SQL ServerµÄ´«µÝֵʱ·¢ÉúÒþʽת»»¡£Ò»Ð©¿ª·¢ÈËÔ±¸üÀÖÒâʹÓà .NET SQLÀàÐÍ£¬ÒòΪËûÃÇÏàÐÅÒþʽת»»»á²úÉúÐÔÄÜËðºÄ¡£µ«ÕâÑùÓÐһЩÏÞÖÆ£¬ÒòΪ .NET SQLÀàÐÍÔÚ¹¦ÄÜ·½Ã沢ûÓÐ .NET±¾»úÀàÐͷḻ¡£ÀýÈ磬.NETµÄ±¾»úÀàÐÍSystem.String£¨C# ÖÐÊÇstring, Visual BasicÊÇString£©ÌṩÁËSubstring·½·¨£¬¶ø .NET SQLµÄ SqlStringÀàÐÍÔòûÓС£
¾¡¹ÜÐÔÄܲ¢²»ÊÇËüÃÇÕæÕýµÄ²î±ð¡£µ«ÎÒ»¹Êǽ¨ÒéÄãÔÚ´´½¨CLR¶ÔÏóµÄ .NET´úÂëÖÐʹÓÃSQLÀàÐÍ£¬ÒòΪ .NET±¾»úÀàÐͲ»Ö§³ÖNULLÖµ¡£ÀýÈ磬Èç¹ûʵÏÖfn_RegExMatchº¯ÊýʱûÓÐʹÓÃSqlStringÀàÐͶøÊÇʹÓà .NET string±¾»úÀàÐÍ×÷Ϊ²ÎÊý£¬ÔÚ´úÂë¼ì²é²ÎÊýÖµÊÇ·ñΪNULLµØ·½Äã»áÊÕµ½Ò»¸ö±àÒë´íÎó¡£Èç¹ûÄãʹÓà .NET string ÀàÐͲ¢Ìø¹ýNULL¼ì²é£¬µ±ÓÃNULL²ÎÊýµ÷ÓÃËüʱº¯Êý½«·µ»ØÒ»¸öÒì³£¡£Èç¹ûÄãÐèÒª .NET±¾»úÀàÐÍÌṩµÄÆäËû¹¦ÄÜ£¬Äã±ØÐëÖ´ÐÐһЩÏÔʽת»»¡£´ËÍ⣬Äã¿ÉÒÔʹÓÃSQLÀàÐͱäÁ¿µÄValueÊôÐԵõ½ .NET±¾»úÀàÐ͵ÄÖµ£¬°Ñ¸ÃÖµ±£´æÔÚÒ»¸ö .NET±¾»úÀàÐ͵ıäÁ¿ÖУ¬ÕâÑù¾Í¿ÉÒÔʹÓñ¾»úÀàÐ͵ÄËùÓг£¹æÊôÐԺͷ½·¨ÁË¡£ÔÚfn_RegExMatchº¯ÊýÖУ¬RegEx.IsMatchÐèÒª .NET string ÀàÐÍ×÷ΪÊäÈ룻ͨ¹ý .NET SQLÀàÐ͵ÄValueÊôÐԵõ½¸ÃÖµ¡£¸Ã·½·¨µÄ·µ»ØÀàÐÍÊÇÒ»¸ö .NET±¾»úÀàÐÍBoolean£¬ËùÒÔ´úÂë°ÑËüÏÔʽת»»ÎªSqlBoolean¡£
ÕâÒ»½Ú½«Ö¤Ã÷Òþʽת»»ºÍÏÔʽת»»Ö®¼äµÄÐÔÄܲîÒìÆäʵ²¢²»ÊǺÜÃ÷ÏÔ¡£ÏÂÃæµÄC# ´úÂ붨ÒåÁ˺¯Êýfn_ImpCastºÍfn_ExpCast£¬Ç°ÕßʹÓà .NET±¾»úÀàÐͺÍÒþʽת»»£¬¶øºóÕßÔòʹÓà .NET SQLÀàÐͺÍÏÔʽת»»¡£
// ±È½ÏÒþʽת»»ºÍÏÔʽת»»
[SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
public static string fn_ImpCast(string inpStr)
{
return inpStr.Substring(2, 3);
}
[SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
public static SqlString fn_ExpCast(SqlString inpStr)
{
return (SqlString)inpStr.ToString().Substring(2, 3);
}
ÏÂÃæÊǶ¨Òå¸Ãº¯ÊýµÄVisual Basic´úÂ룺
'±È½ÏÒþʽת»»ºÍÏÔʽת»»
<SqlFunction(IsDeterministic:=True, DataAccess:=DataAccessKind.None)> _
Public Shared Function fn_ImpCast(ByVal inpStr As String) As String
Return inpStr.Substring(2, 3)
End Function
<SqlFunction(IsDeterministic:=True, DataAccess:=DataAccessKind.None)> _
Public Shared Function fn_ExpCast(ByVal inpStr As SqlString) As SqlString
Return CType(inpStr.ToString().Substring(2, 3), SqlString)
End Function
ÏÂÃæÊÇÔÚÊý¾Ý¿âÖÐ×¢²áC#°æº¯ÊýµÄ´úÂ룺
IF OBJECT_ID('dbo.fn_ImpCast') IS NOT NULL
DROP FUNCTION dbo.fn_ImpCast;
GO
IF OBJECT_ID('dbo.fn_ExpCast') IS NOT NULL
DROP FUNCTION dbo.fn_ExpCast;
GO
-- ´´½¨ fn_ImpCast º¯Êý
CREATE FUNCTION dbo.fn_ImpCast(@inpstr AS NVARCHAR(4000))
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.CLRUtilities.fn_ImpCast;
GO
-- ´´½¨ fn_ExpCast º¯Êý
CREATE FUNCTION dbo.fn_ExpCast(@inpstr AS NVARCHAR(4000))
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.CLRUtilities.fn_ExpCast;
ÏÂÃæµÄ´úÂë×¢²áVisual Basic°æµÄº¯Êý£º
--´´½¨fn_ImpCastº¯Êý
CREATE FUNCTION dbo.fn_ImpCast(@inpstr AS NVARCHAR(4000))
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.[CLRUtilities.CLRUtilities].fn_ImpCast;
GO
-- ´´½¨fn_ExpCastº¯Êý
CREATE FUNCTION dbo.fn_ExpCast(@inpstr AS NVARCHAR(4000))
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.[CLRUtilities.CLRUtilities].fn_ExpCast;
ÏÂÃæµÄ´úÂëͨ¹ýÑ»·µ÷ÓÃÒ»°ÙÍò´Îfn_ImpCast£¬ÔËÐÐÁË16Ã룺
SET NOCOUNT ON;
GO
DECLARE @a AS NVARCHAR(4000);
DECLARE @i AS INT;
SET @i = 1;
WHILE @i <= 1000000
BEGIN
SET @a = dbo.fn_ImpCast(N'123456');
SET @i = @i + 1;
END
ÏÂÃæµÄ´úÂëµ÷ÓÃfn_ExpCastº¯Êý, ÔËÐÐÁË17Ãë:
DECLARE @a AS NVARCHAR(4000);
DECLARE @i AS INT;
SET @i = 1;
WHILE @i <= 1000000
BEGIN
SET @a = dbo.fn_ExpCast(N'123456');
SET @i = @i + 1;
END
ÈçÄãËù¼û£¬²î±ð²»ÊǺÜÃ÷ÏÔ£¬ÔÚÕâ¸ö²âÊÔÖÐÒþʽת»»·½·¨ÉõÖÁ»¹Òª±ÈÏÔʽת»»·½·¨ÉÔ¿ìһЩ¡£
Íê³Éºó£¬ÔËÐÐÏÂÃæµÄ´úÂë½øÐÐÇåÀí¡£
IF OBJECT_ID('dbo.fn_ImpCast') IS NOT NULL
DROP FUNCTION dbo.fn_ImpCast;
GO
IF OBJECT_ID('dbo.fn_ExpCast') IS NOT NULL
DROP FUNCTION dbo.fn_ExpCast;
SQLÇ©Ãû(SQL Signature)
ÕâÒ»½ÚÌṩһ¸öº¯ÊýµÄT-SQLºÍCLRÁ½ÖÖʵÏÖ£¬¸Ãº¯Êý·µ»Ø²éѯ×Ö·û´®µÄÇ©Ãû¡£Ë¼Â·ÊǽÓÊÕ²éѯ×Ö·û´®×÷ΪÊäÈë²¢·µ»Ø±íʾ¸Ã²éѯ¡°Ç©Ãû¡±»ò¡°Ä£°å¡±µÄ×Ö·û´®¡£ÔÚÕâ¸öÇ©ÃûÖУ¬³öÏÖÔÚÊäÈë²éѯ×Ö·û´®ÖеÄËùÓÐ×ÖÃæÖµ£¨literal£©¶¼±»Ì滻Ϊһ¸öͨÓõķûºÅ£¨ÔÚÕâ¸öÀý×ÓÖÐÊÇ# £©¡£ÀýÈ磬¼ÙÉèÄãʹÓÃÏÂÃæµÄ²éѯ×Ö·û´®¡£
N'SELECT * FROM dbo.T1 WHERE col1 = 3 AND col2 > 78;'
ÄãÏ£ÍûµÃµ½ÏÂÃæµÄ×Ö·û´®£º
N'SELECT * FROM dbo.T1 WHERE col1 = # AND col2 > #'
µ±Äã°Ñ¸ú×Ùµ½µÄSQLÓï¾ä²åÈëÒ»¸ö±íºóÔÙͨ¹ýÕâЩÊý¾ÝÀ´Í³¼Æ²éѯµÄÐÔÄÜʱ£¬ÕâÑùµÄº¯Êý»á·Ç³£ÓÐÓá£Èç¹ûÄãÖ±½Ó°´Ôʼ²éѯ×Ö·û´®·Ö×飬Âß¼ÉÏÏàͬµÄ²éѯ»á±»·Åµ½²»Í¬µÄ×éÖС£Í³¼ÆÕâЩ²éѯǩÃûµÄÐÔÄܽ«ÎªÄãÌṩ¸üʵÓøüÓмÛÖµµÄÐÅÏ¢¡£
T-SQL SQLÇ©ÃûUDF
Äã¿ÉÒÔÔÚ´úÂëÇåµ¥6-2ÖÐÕÒµ½SQLÇ©Ãûº¯ÊýµÄT-SQLʵÏÖ¡£ÎÒÒª¸ÐлStuart Ozer£¬ÊÇËû±àдÁËÕâ¸öº¯Êý£¬²¢ÔÊÐíÎÒÔÚÕâ±¾ÊéÖÐʹÓá£StuartÊÇMicrosoft SQL Server Customer Advisory TeamµÄ³ÉÔ±¡£
´úÂëÇåµ¥6-2 ´´½¨fn_SQLSigTSQL UDFµÄ½Å±¾
IF OBJECT_ID('dbo.fn_SQLSigTSQL') IS NOT NULL
DROP FUNCTION dbo.fn_SQLSigTSQL;
GO
CREATE FUNCTION dbo.fn_SQLSigTSQL
(@p1 NTEXT, @parselength INT = 4000)
RETURNS NVARCHAR(4000)
--
--¸Ãº¯ÊýÒÔ¡°ÏÖ×´¡±ÌṩÇÒûÓÐÈκε£±£
--ͬʱҲûÓÐÊÚÓèÈκÎȨÀû -- ʹÓøú¯ÊýËù°üº¬µÄ½Å±¾Ê¾ÀýÊÜÏÂÁÐÌõ¿îÔ¼Êø
-- http://www.microsoft.com/info/cpyright.htm
--
-- ·Ö½â²éѯ×Ö·û´®
AS
BEGIN
DECLARE @pos AS INT;
DECLARE @mode AS CHAR(10);
DECLARE @maxlength AS INT;
DECLARE @p2 AS NCHAR(4000);
DECLARE @currchar AS CHAR(1), @nextchar AS CHAR(1);
DECLARE @p2len AS INT;
SET @maxlength = LEN(RTRIM(SUBSTRING(@p1,1,4000)));
SET @maxlength = CASE WHEN @maxlength > @parselength
THEN @parselength ELSE @maxlength END;
SET @pos = 1;
SET @p2 = '';
SET @p2len = 0;
SET @currchar = '';
set @nextchar = '';
SET @mode = 'command';
WHILE (@pos <= @maxlength)
BEGIN
SET @currchar = SUBSTRING(@p1,@pos,1);
SET @nextchar = SUBSTRING(@p1,@pos+1,1);
IF @mode = 'command'
BEGIN
SET @p2 = LEFT(@p2,@p2len) + @currchar;
SET @p2len = @p2len + 1 ;
IF @currchar IN (',','(',' ','=','<','>','!')
AND @nextchar BETWEEN '0' AND '9'
BEGIN
SET @mode = 'number';
SET @p2 = LEFT(@p2,@p2len) + '#';
SET @p2len = @p2len + 1;
END
IF @currchar = ''''
BEGIN
SET @mode = 'literal';
SET @p2 = LEFT(@p2,@p2len) + '#''';
SET @p2len = @p2len + 2;
END
END
ELSE IF @mode = 'number' AND @nextchar IN (',',')',' ','=','<','>','!')
SET @mode= 'command';
ELSE IF @mode = 'literal' AND @currchar = ''''
SET @mode= 'command';
SET @pos = @pos + 1;
END
RETURN @p2;
END
GO
fn_SQLSigTSQLº¯Êý½ÓÊÕÁ½¸öÊäÈë²ÎÊý£º@p1ÊÇÊäÈëµÄ²éѯ×Ö·û´®£¬@parselengthÊÇÄãÒª·ÖÎöµÄ×î´ó×Ö·û¸öÊý¡£Èç¹û @parselengthСÓÚ @p1ÖеIJéѯ×Ö·û´®µÄ³¤¶È£¬º¯Êý½«Ö»·ÖÎö×î×ó±ßµÄ @parselength¸ö×Ö·û¡£¸Ãº¯ÊýÒ»´Î±éÀú×Ö·û´®ÖеÄÒ»¸ö×Ö·û¡£ÔÚ @mode±äÁ¿±£´æÒ»¸ö״ֵ̬£¬¸Ã±äÁ¿¿ÉÄÜÊÇÏÂÁÐÖµÖ®Ò»£º¡®command¡¯¡¢¡®number¡¯ »ò ¡®literal¡¯¡£
CommandÊÇĬÈϵÄ״̬£¬Ëü±íʾµ±Ç°µÄ×Ö·û½«±»´®Áªµ½Êä³ö×Ö·û´®ÖС£Number±íʾʶ±ð³öÒ»¸öÊý×Ö×ÖÃæÖµ£¨number literal£©£¬Õâʱ½«´®Áª# ·ûºÅ¡£µ±¶ººÅ¡¢×óÀ¨ºÅ¡¢¿Õ¸ñ»òÔËËã·ûºóÃæ¸úÒ»¸öÊý×Öʱ±êʶһ¸öÊý×Ö×ÖÃæÖµ¡£µ±ÏÂÒ»¸ö×Ö·ûÊǶººÅ¡¢ÓÒÀ¨ºÅ¡¢¿Õ¸ñ»òÔËËã·ûʱ״̬´ÓNumberתµ½Command¡£Literal±íʾ±êʶÁËÒ»¸ö×Ö·û´®×ÖÃæÖµ, Õâʱ½«´®Áª×Ö·û´®' # '¡£µ±¼ì²âµ½×óÒýºÅʱ±êʶһ¸ö×Ö·û´®×ÖÃæÖµ¡£µ±¼ì²âµ½ÓÒÒýºÅʱ״̬´Óliteralתµ½command¡£
Òª²âÊÔfn_SQLSigTSQLº¯Êý£¬ÔËÐÐÏÂÃæµÄ´úÂ룺
SELECT dbo.fn_SQLSigTSQL
(N'SELECT * FROM dbo.T1 WHERE col1 = 3 AND col2 > 78', 4000);
Êä³öÈçÏ£º
SELECT * FROM dbo.T1 WHERE col1 = # AND col2 > #
CLR SQL Ç©Ãû UDF
´úÂëÇåµ¥6-3ºÍ6-4°üº¬ÁËSQLÇ©Ãûº¯ÊýµÄC# ºÍ Visual BasicʵÏÖ¡£¸Ãº¯ÊýµÄ .NET°æ±¾¸Ä±à×ÔStuartµÄËã·¨¡£ÓÉAndrew J. Kelly ºÍ Dejan Sarka¿ª·¢£¬ËûÃǶ¼ÊÇSolid Quality LearningµÄ¹ËÎʺÍÖøÃûµÄSQL Server MVP¡£¸Ãº¯ÊýµÄ .NET°æ±¾Óë´úÂëÇåµ¥6-2ÖеÄT-SQL°æ±¾ÏàËÆ£¬Ìṩ¸Ã°æ±¾Ö»ÊÇΪÁËÐÔÄܲâÊԺͱȽ϶øÒÑ¡£ÔÚ±¾ÕµĺóÃæ£¬ÎÒ½«ÃèÊöʹÓÃÕýÔò±í´ïʽÉú³É²éѯǩÃûµÄ¸üΪǿ´óµÄ»ùÓÚCLRµÄ½â¾ö·½°¸¡£
´úÂëÇåµ¥6-3 C# °æµÄfn_SQLSigCLRº¯Êý
// SQL Ç©Ãû
[SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
public static SqlString fn_SQLSigCLR(SqlString inpRawString,
SqlInt32 inpParseLength)
{
if (inpRawString.IsNull)
return SqlString.Null;
int pos = 0;
string mode = "command";
string RawString = inpRawString.Value;
int maxlength = RawString.Length;
StringBuilder p2 = new StringBuilder();
char currchar = ' ';
char nextchar = ' ';
int ParseLength = RawString.Length;
if (!inpParseLength.IsNull)
ParseLength = inpParseLength.Value;
if (RawString.Length > ParseLength)
{
maxlength = ParseLength;
}
while (pos < maxlength)
{
currchar = RawString[pos];
if (pos < maxlength - 1)
{
nextchar = RawString[pos + 1];
}
else
{
nextchar = RawString[pos];
}
if (mode == "command")
{
p2.Append(currchar);
if ((",( =<>!".IndexOf(currchar) >= 0)
&&
(nextchar >= '0' && nextchar <= '9'))
{
mode = "number";
p2.Append('#');
}
if (currchar == '\'')
{
mode = "literal";
p2.Append("#'");
}
}
else if ((mode == "number")
&&
(",( =<>!".IndexOf(nextchar) >= 0))
{
mode = "command";
}
else if ((mode == "literal") && (currchar == '\''))
{
mode = "command";
}
pos++;
}
return p2.ToString ();
}
´úÂëÇåµ¥6-4 Visual Basic°æµÄfn_SQLSigCLRº¯Êý
' SQL Ç©Ãû
<SqlFunction(IsDeterministic:=True, DataAccess:=DataAccessKind.None)> _
Public Shared Function fn_SQLSigCLR(ByVal inpRawString As SqlString, _
ByVal inpParseLength As SqlInt32) As SqlString
If inpRawString.IsNull Then
Return SqlString.Null
End If
Dim pos As Integer = 0
Dim mode As String = "command"
Dim RawString As String = inpRawString.Value
Dim maxlength As Integer = RawString.Length
Dim p2 As StringBuilder = New StringBuilder()
Dim currchar As Char = " "c
Dim nextchar As Char = " "c
Dim ParseLength As Integer = RawString.Length
If (Not inpParseLength.IsNull) Then
ParseLength = inpParseLength.Value
End If
If (RawString.Length > ParseLength) Then
maxlength = ParseLength
End If
While (pos < maxlength)
currchar = RawString(pos)
If (pos < maxlength - 1) Then
nextchar = RawString(pos + 1)
Else
nextchar = RawString(pos)
End If
If (mode = "command") Then
p2.Append(currchar)
If ((",( =<>!".IndexOf(currchar) >= 0) _
And _
(nextchar >= "0"c And nextchar <= "9"c)) Then
mode = "number"
p2.Append("#")
End If
If (currchar = "'"c) Then
mode = "literal"
p2.Append("#")
End If
ElseIf ((mode = "number") And _
(",( =<>!".IndexOf(nextchar) >= 0)) Then
mode = "command"
ElseIf ((mode = "literal") And _
(currchar = "'"c)) Then
mode = "command"
End If
pos=pos+1
End While
Return p2.ToString
End Function
ʹÓÃÏÂÃæµÄ´úÂë×¢²áC# °æfn_SQLSigCLRº¯Êý£º
IF OBJECT_ID('dbo.fn_SQLSigCLR') IS NOT NULL
DROP FUNCTION dbo.fn_SQLSigCLR;
GO
CREATE FUNCTION dbo.fn_SQLSigCLR
(@rawstring AS NVARCHAR(4000), @parselength AS INT)
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.CLRUtilities.fn_SQLSigCLR;
Èç¹ûÄãʹÓÃVisual BasicʵÏָú¯Êý£¬Ê¹ÓÃÏÂÃæµÄ´úÂë½øÐÐ×¢²á£º
CREATE FUNCTION dbo.fn_SQLSigCLR
(@rawstring AS NVARCHAR(4000), @parselength AS INT)
RETURNS NVARCHAR(4000)
EXTERNAL NAME CLRUtilities.[CLRUtilities.CLRUtilities].fn_SQLSigCLR;
ÔËÐÐÏÂÃæµÄ´úÂë²âÊÔfn_SQLSigCLRº¯Êý£º
SELECT dbo.fn_SQLSigCLR
(N'SELECT * FROM dbo.T1 WHERE col1 = 3 AND col2 > 78', 4000);
µÃµ½µÄÊä³öÈçÏ£º
SELECT * FROM dbo.T1 WHERE col1 = # AND col2 > #
±È½ÏT-SQL ºÍ CLR SQL Ç©Ãû UDFµÄÐÔÄÜ
ÔÚ×Ö·û´®´¦Àí·½Ãæ .NET´úÂë±ÈT-SQL¸ü¿ì¡£SQLÇ©Ãûº¯Êý¾ÍÊÇÒ»¸ö¿ÉÒÔÑÝʾÕâÖÖÐÔÄܲîÒìµÄ¼«ºÃµÄÀý×Ó£¬ÓÈÆäÊÇÁ½¸ö°æ±¾ÊµÏÖµÄÊÇͬһ¸öËã·¨¡£ÄãÂíÉϾͻῴµ½ËüÃÇÔÚ×Ö·û´®´¦Àí·½ÃæµÄÐÔÄܲîÒì¡£
Ê×ÏÈ£¬ÔËÐÐÏÂÃæµÄ´úÂë´´½¨Queries±í²¢ÓÃ100 000¸ö²éѯ×Ö·û´®Ìî³ä¸Ã±í£º
IF OBJECT_ID('dbo.Queries') IS NOT NULL
DROP TABLE dbo.Queries;
GO
SELECT CAST(N'SELECT * FROM dbo.T1 WHERE col1 = 3 AND col2 > 78'
AS NVARCHAR(MAX)) AS query
INTO dbo.Queries
FROM dbo.Nums
WHERE n <= 100000;
´ò¿ªSSMSÖеÄÖ´Ðкó·ÅÆú½á¹ûÑ¡Ïî¡£
µ±ÎÒÔËÐÐÏÂÃæÕâÐÐʹÓÃÁËT-SQL°æº¯ÊýµÄ´úÂëʱ£¬ÓÃÁ˽«½ü100Ãë¡£
SELECT dbo.fn_SQLSigTSQL(query, 4000) FROM dbo.Queries;
¶ø¸Ãº¯ÊýµÄCLR C# °æÔÚ1ÃëÖÓÖ®ÄÚ¾ÍÍê³ÉÁË£¬Visual Basic°æÓÃÁË2ÃëÖÓ¡£
SELECT dbo.fn_SQLSigCLR(query, 4000) FROM dbo.Queries;
¹Ø±ÕSSMSÉϵÄÖ´Ðкó·ÅÆú½á¹ûÑ¡Ïî¡£
ÈçÄãËù¼û£¬¸Ãº¯ÊýµÄCLR°æ±¾´ó¸Å±ÈT-SQL°æ±¾¿ì100±¶¡£
¾ÍÏñÎÒÔøÌáµ½µÄ£¬fn_SQLSigCLRº¯ÊýʵÏÖµÄËã·¨ºÍfn_SQLSigTSQLº¯ÊýÏàͬ£¬ÌṩËüÖ»ÊÇΪÁËÐÔÄܱȽϡ£Äã¿ÉÒÔʹÓÃÕýÔò±í´ïʽʵÏÖ¸üΪǿ´óµÄ»ùÓÚCLRµÄ½â¾ö·½°¸¡£ÎÒÒÔÇ°ÔøÏòÄãչʾ¹ýÈçºÎʹÓÃÕýÔò±í´ïʽ½øÐÐģʽƥÅ䣬ËüÓÃÓÚ¼ì²éÒ»¸ö×Ö·û´®ÊÇ·ñÆ¥Åäijģʽ¡£ÄãÒ²¿ÉÒÔʹÓÃÕýÔò±í´ïʽʵÏÖ»ùÓÚģʽ£¨pattern-based£©µÄÌæ»»¡£¼´£¬Äã¿ÉÒÔʹÓÃÒ»¸öÄ£Ê½Ìæ»»×Ö·û´®ÖгöÏֵįäËûģʽ¡£ÏÂÃæÊÇfn_RegExReplaceº¯ÊýµÄC# ¶¨Ò壬Ëüµ÷ÓÃRegex¶ÔÏóµÄReplace·½·¨£º
// fn_RegExReplace ¨C»ùÓÚÕýÔò±í´ïʽµÄͨÓÃÌæ»»
[SqlFunction(IsDeterministic = true, DataAccess = DataAccessKind.None)]
public static SqlString fn_RegExReplace(
SqlString input, SqlString pattern, SqlString replacement)
{
if (input.IsNull || pattern.IsNull || replacement.IsNull)
return SqlString.Null;
else
return (SqlString)Regex.Replace(
input.Value, pattern.Value, replacement.Value);
}
ÏÂÃæÊǸú¯ÊýµÄVisual Basic¶¨Ò壺
' fn_RegExReplace -»ùÓÚÕýÔò±í´ïʽµÄͨÓÃÌæ»»
<SqlFunction(IsDeterministic:=True, DataAccess:=DataAccessKind.None)> _
Public Shared Function fn_RegExReplace( _
ByVal input As SqlString, ByVal pattern As SqlString, _
ByVal replacement As SqlString) As SqlString
If (input.IsNull Or pattern.IsNull Or replacement.IsNull) Then
Return SqlString.Null
Else
Return CType(Regex.Replace( _
input.Value, pattern.Value, replacement.Value), SqlString)
End If
End Function
¸Ãº¯Êý½ÓÊÕÈý¸öÊäÈë²ÎÊý£ºinput¡¢patternºÍreplacement¡£º¯ÊýÊ×Ïȼì²é²ÎÊýÖµÊÇ·ñΪNull£¬Èç¹ûÊÇÔò·µ»ØNull¡£Èç¹û²ÎÊýÖµ¶¼²»ÎªNull£¬Ôòº¯Êýµ÷ÓÃRegex.Replace·½·¨£¬¸Ã·½·¨ÓÃreplacementÄ£Ê½Ìæ»»input×Ö·û´®ÄÚ³öÏÖµÄÿ¸öpattern¡£ÏÂÃæÎÒÀ´ÑÝʾÈçºÎʹÓÃfn_RegExReplaceº¯ÊýÉú³É²éѯǩÃû£¬µ±È»ÄãÒ²¿ÉÒ԰Ѹú¯ÊýÓÃÓÚÆÕͨµÄ»ùÓÚģʽµÄ×Ö·û´®Ìæ»»¡£
ʹÓÃÏÂÃæµÄ´úÂë×¢²áC# °æµÄfn_RegExReplaceº¯Êý¡£
IF OBJECT_ID('dbo.fn_RegExReplace') IS NOT NULL
DROP FUNCTION dbo.fn_RegExReplace;
GO
CREATE FUNCTION dbo.fn_RegExReplace(
@input AS NVARCHAR(MAX),
@pattern AS NVARCHAR(MAX),
@replacement AS NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
WITH RETURNS NULL ON NULL INPUT
EXTERNAL NAME CLRUtilities.CLRUtilities.fn_RegExReplace;
Èç¹ûÄãÓÃVisual BasicʵÏָú¯Êý£¬Ê¹ÓÃÏÂÃæµÄ´úÂë½øÐÐ×¢²á¡£
CREATE FUNCTION dbo.fn_RegExReplace(
@input AS NVARCHAR(MAX),
@pattern AS NVARCHAR(MAX),
@replacement AS NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
WITH RETURNS NULL ON NULL INPUT
EXTERNAL NAME CLRUtilities.[CLRUtilities.CLRUtilities].fn_RegExReplace;
ÏÂÃæÊÇÒ»¸öʾÀý£¬ËüÑÝʾÁËÈçºÎʹÓøú¯ÊýΪQueries±íÖвéѯ×Ö·û´®µÄÉú³É²éѯǩÃû¡£
SELECT
dbo.fn_RegExReplace(query,
N'([\s,(=<>!](?![^\]]+[\]]))(?:(?:(?:(?# expression coming
)(?:([N])?('')(?:[^'']|'''')*(''))(?# character
)|(?:0x[\da-fA-F]*)(?# binary
)|(?:[-+]?(?:(?:[\d]*\.[\d]*|[\d]+)(?# precise number
)(?:[eE]?[\d]*)))(?# imprecise number
)|(?:[~]?[-+]?(?:[\d]+))(?# integer
))(?:[\s]?[\+\-\*\/\%\&\|\^][\s]?)?)+(?# operators
))',
N'$1$2$3#$4')
FROM dbo.Queries;
½áºÏÄÚÖõÄ×¢ÊÍ£¬ÕâЩģʽºÜÈÝÒ×Àí½â¡£ËüÄÜʶ±ð£¨²¢ÓÃ#·ûºÅÌæ»»£©±Èfn_SQLSigCLRº¯Êý¸ü¶àµÄ×ÖÃæÖµÀàÐÍ¡£Ëü¿ÉÒÔʶ±ð×Ö·û×ÖÃæÖµ¡¢¶þ½øÖÆ×ÖÃæÖµ¡¢¾«È·Êý×Ö¡¢½üËÆÊý×Ö£¬ÉõÖÁ¿ÉÒÔʶ±ð°üº¬×ÖÃæÖµµÄ»ìºÏ±í´ïʽ£¨fold expression£©£¬²¢ÓÃ#·ûºÅÌæ»»ËüÃÇ¡£Ïà¶ÔÓÚfn_SQLSigCLRº¯Êý£¬¸Ã½â¾ö·½°¸»¹ÓÐÒ»¸öÓÅÊÆ£¬Äã¿ÉÒÔά»¤×Ô¼ºµÄÕýÔò±í´ïʽ²¢ÔöÇ¿ËüÃǵŦÄÜÒÔÖ§³Ö¸ü¶àµÄÇé¿ö£¬¶øÇÒ²»ÐèÒªÐ޸ĸú¯ÊýµÄ¶¨Ò塣Ȼ¶ø£¬Í¨¹ýÕýÔò±í´ïʽËùÔöÇ¿µÄ¹¦ÄÜÐèÒªÒ»¶¨µÄ³É±¾£¬ÉÏÃæµÄ²éѯ´ó¸Å»áÔËÐÐ12Ã룬±Èfn_SQLSigCLRº¯ÊýÂýÁË12±¶£¬µ«»¹ÊDZÈfn_SQLSigTSQLº¯Êý¿ì8±¶¡£
Ìáʾ Äã¿ÉÄÜÏë´´½¨Ò»Ð©¾ßÓиü¹ã·ºÓÃ;µÄº¯Êý£¬±ÈÈç,²»ÓÃΪº¯ÊýÃû³ÆÏÞ¶¨Êý¾Ý¿â(CLRUtilities.dbo.fn_RegExReplace)¾Í¿ÉÒÔÔÚËùÓÐÊý¾Ý¿âÖзÃÎÊfn_RegExReplace¡£Îª´Ë£¬ÔÚÿ¸öҪʹÓøú¯ÊýµÄÊý¾Ý¿âÖд´½¨Ò»¸ö¸Ãº¯ÊýµÄͬÒå´Ê(synonym)£¬ÎªÁËÄÜÔÚNorthwindÊý¾Ý¿âÖÐʹÓøú¯Êý£¬ÔËÐÐÏÂÃæµÄ´úÂ룺
USE Northwind;
GO
CREATE SYNONYM dbo.fn_RegExReplace
FOR CLRUtilities.dbo.fn_RegExReplace;
Èç¹ûÄãÔÚmodelÊý¾Ý¿â´´½¨ÁËÒ»¸öͬÒå´Ê£¬ÒÔºóÄã´´½¨µÄÿ¸öÐÂÊý¾Ý¿â¶¼»á´´½¨Õâ¸öͬÒå´Ê£¬ÒòΪÐÂÊý¾Ý¿â¶¼ÊÇÒÔmodel¸±±¾µÄ·½Ê½´´½¨µÄ¡£ÕâͬÑùÒ²Ó¦ÓÃÓÚtempdbÊý¾Ý¿â£¬ËüÔÚÿ´ÎÖØÆô¶¯SQL Serverʱ±»´´½¨¡£
Íê³Éºó£¬ÔËÐÐÏÂÃæµÄ´úÂë½øÐÐÇåÀí¡£
USE Northwind;
GO
IF OBJECT_ID('dbo.fn_RegExReplace', 'SN') IS NOT NULL
DROP SYNONYM dbo.fn_RegExReplace;
GO
USE CLRUtilities;
GO
IF OBJECT_ID('dbo.fn_SQLSigTSQL') IS NOT NULL
DROP FUNCTION dbo.fn_SQLSigTSQL;
GO
IF OBJECT_ID('dbo.fn_SQLSigCLR') IS NOT NULL
DROP FUNCTION dbo.fn_SQLSigCLR;
GO
IF OBJECT_ID('dbo.fn_RegExReplace') IS NOT NULL
DROP FUNCTION dbo.fn_RegExReplace;
GO






