使用 Nullif 作为条件的一部分

Using Nullif as part of a condition

我目前所处的场景是,我们有一个笨重、陈旧、庞大的数据库,为我们的一两个用户不太友好的系统提供支持(这是由第三方控制的,所以我不能改变那个)。

展望未来,我希望将必要的数据推送到一个新的(结构更好的)数据库中,并实施一种机制来保持两者之间的数据同步。

这个旧数据库的一个古怪特征是,它不使用空值,而是使用空字符串并将它们视为空值。

在新数据库中,我想在没有数据的地方使用空值(因为我想不出有什么好的理由不这样做)。

我的问题是当我将数据从旧数据库提取到新数据库时(使用 MERGE 语句),我正在使用 NULLIF([myCol], '') 来检查实际上是否有任何数据 -如果不是,则将其视为 null。

例如,在为学生同步数据时,我计划按照以下方式做一些事情(数据库和模式的名称与问题无关,所以我对结构进行了一些匿名处理) :

USE [NewDB];

DROP TABLE IF EXISTS #myTempTable;

SELECT *
INTO #myTempTable
FROM [OldDB].[schemaName].[Students];

MERGE [schema].[Person] p
USING #myTempTable s 
      ON TRIM(s.STUD_ISN) = p.StudentDBID
--WHEN MATCHED and not equal, update
WHEN NOT MATCHED 
        THEN INSERT (
                        [Surname] ,
                        [PreferredSurname] ,
                        [FormerSurname] ,
                        [Forename] ,
                        [MiddleNames] , 
                        [PreferredForename] ,
                        [DoB] ,
                        [Gender] ,
                        [GenderIdentity] ,
                        [Title] ,
                        [Deceased] ,
                        [DeceasedDate] ,
                        [StudentDBID])
             VALUES ( 
                        NULLIF(TRIM([s].[STUD_Surname]), '') ,
                        NULLIF(TRIM([s].[STUD_Preferred_Surname]), '')  ,
                        NULLIF(TRIM([s].STUD_Former_Surname), '')  ,
                        NULLIF(TRIM([s].[STUD_Forename_1]), '')  ,
                        NULLIF(TRIM([s].[STUD_Forename_2]), '')  ,
                        NULLIF(TRIM([s].[STUD_Known_As]), '')  ,
                        [s].[STUD_DOB] ,
                        NULLIF(TRIM([s].[STUD_Gender]), '')  ,
                        NULLIF(TRIM([s].STUD_Gender_Identity), '')  ,
                        NULLIF(TRIM([s].STUD_Title), '')  ,
                        [s].STUD_Deceased ,
                        [s].STUD_Date_of_Death ,
                        TRIM([s].STUD_ISN)
                    );

现在,显然当前查询只处理以下场景:

The old database has data and the new one doesn't

因为我对以下场景的逻辑有些不满:

The new database has the corresponding record, but it needs updating.

对于基于文本的字段,有 3 种不同的情况需要更新“新”数据:

  1. 两个值都不是 null/empty,但它们不相等
  2. “旧”数据库中的记录是 null/empty 而“新”数据库中的记录不是
  3. “新”数据库中的记录为空,“旧”数据库中没有

我希望做一些相对简单的事情,例如:

WHEN MATCHED AND ( 
                    (NULLIF(TRIM([s].[STUD_Surname]), '') IS NOT NULL
                        AND p.Surname IS NULL)
                    OR (NULLIF(TRIM([s].[STUD_Surname]), '') IS NULL
                        AND p.Surname IS NOT NULL)
                    OR (NULLIF(TRIM([s].[STUD_Surname]), '') != p.Surname)
                 ) -- do the same for the other columns
THEN UPDATE SET
                Surname = s.STUD_Surname

但是,NULLIF(TRIM([s].[STUD_Surname]), '') IS NOT NULL显然无效?

我最好的选择是在 WHEN MATCHED 子句中将 NULLIF 换成 ISNULL ......还是我错过了一些可以提高效率的东西?

您可以使用 SQL 中可用的合并功能来获得所需的结果

它将return来自传递参数的第一个非空值

SELECT合并(空,'First Non Null','Alex')

COALESCE Keyword

可以简化更新检查。

因为源温度 table 没有 NULL。
您只需要比较修剪后的值。

MERGE Person t
USING #tmpTable s 
   ON s.STUD_ISN = t.StudentDBID
WHEN NOT MATCHED THEN 
  INSERT (
    StudentDBID
  , Forename
  , PreferredForename
  , Surname
  )
  VALUES (
    NULLIF(TRIM(s.STUD_ISN), '')
  , NULLIF(TRIM(s.STUD_Forename), '')
  , NULLIF(TRIM(s.STUD_Forename_1), '')
  , NULLIF(TRIM(s.STUD_Surname), '')
  )
WHEN MATCHED
AND (
     COALESCE(t.Forename, '') != TRIM(s.STUD_Forename)
  OR COALESCE(t.PreferredForename, '') != TRIM(s.STUD_Forename_1)
  OR COALESCE(t.Surname, '') != TRIM(s.STUD_Surname)
) 
THEN 
UPDATE SET
  UpdatedOn = SYSDATETIME()
, Forename = NULLIF(TRIM(s.STUD_Forename), '')
, PreferredForename = NULLIF(TRIM(s.STUD_Forename_1), '')
, Surname = NULLIF(TRIM(s.STUD_Surname), '')
;
SELECT *
FROM Person
StudentDBID | Forename | PreferredForename | Surname | UpdatedOn                   | CreatedOn                  
:---------- | :------- | :---------------- | :------ | :-------------------------- | :--------------------------
B9701       | Bob      | Bobby             | Modest  | 2022-01-14 12:58:05.9862269 | 2022-01-14 12:58:05.9862269
J0402       | Jane     | JD                | Doe     | 2022-01-14 12:58:05.9862269 | 2022-01-14 12:58:05.9862269
J0504       | Jim      | Jimmy             | Savage  | null                        | 2022-01-14 12:58:05.9862269
J7201       | John     | null              | Doe     | null                        | 2022-01-14 12:58:05.9862269
M0803       | Mike     | null              | Hammer  | 2022-01-14 12:58:05.9862269 | 2022-01-14 12:58:05.9862269

演示 db<>fiddle here

最后,我的解决方案是在 SELECT .... Into .... 块中应用各种函数。像这样:

ALTER PROCEDURE [NGSync].[spFullStudentSync]
AS
BEGIN
    SET NOCOUNT ON;

    DROP TABLE IF EXISTS #students

    SELECT [STUD_ISN],
           NULLIF(TRIM([STUD_Student_ID]), '') AS [STUD_Student_ID] ,
           NULLIF(TRIM([STUD_Surname]), '') AS [STUD_Surname] ,
           NULLIF(TRIM([STUD_Forename_1]), '') AS [STUD_Forename_1] ,
           NULLIF(TRIM([STUD_Forename_2]), '') AS [STUD_Forename_2] ,
           NULLIF(TRIM([STUD_Known_As]), '') AS [STUD_Known_As] ,
           [STUD_DOB] ,
           NULLIF(TRIM([STUD_Gender]) , '') AS [STUD_Gender],
           NULLIF(TRIM([STUD_Title]) , '') AS [STUD_Title],
           NULLIF(TRIM([STUD_Ethnicity]) , '') AS [STUD_Ethnicity],
           NULLIF(TRIM([STUD_LDDHP]) , '') AS [STUD_LDDHP],
           NULLIF(TRIM([STUD_Home_Telephone_No] ) , '') AS [STUD_Home_Telephone_No] ,
           NULLIF(TRIM([STUD_Daytime_Telephone] ) , '') AS [STUD_Daytime_Telephone] ,
           NULLIF(TRIM([STUD_Mobile_Telephone] ) , '') AS [STUD_Mobile_Telephone] ,
           NULLIF(TRIM([STUD_EMail_Address] ) , '') AS [STUD_EMail_Address] ,
           NULLIF(TRIM([STUD_Former_Surname] ) , '') AS [STUD_Former_Surname] ,
           CAST( CASE WHEN NULLIF(TRIM([STUD_Deceased] ) , '') = 'D' THEN 1 else 0 end AS bit ) AS [STUD_Deceased] ,
           NULLIF(TRIM([STUD_Deletion_Flag] ) , '') AS [STUD_Deletion_Flag] ,
           [STUD_Delete_Merge]  ,
           NULLIF(TRIM([STUD_Photo_filename] ) , '') AS [STUD_Photo_filename] ,
           NULLIF(TRIM([STUD_Nationality] ) , '') AS [STUD_Nationality] ,
           [STUD_Date_of_Entry_in_UK] ,
           NULLIF(TRIM([STUD_Student_Type_FESR] ) , '') AS [STUD_Student_Type_FESR] ,
           [STUD_School_ISN] ,
           NULLIF(TRIM([STUD_Home_LEA] ) , '') AS [STUD_Home_LEA] ,
           NULLIF(TRIM([STUD_Employer_Code] ) , '') AS [STUD_Employer_Code] ,
           NULLIF(TRIM([STUD_Religion] ) , '') AS [STUD_Religion] ,
           NULLIF(TRIM([STUD_Location] ) , '') AS [STUD_Location] ,
           [STUD_TPS_Include] ,
           [STUD_QOE_Complete] ,
           NULLIF(TRIM([STUD_UCAS_Application_Code] ) , '') AS [STUD_UCAS_Application_Code] ,
           [STUD_MIAP_Consent_Status] ,
           [STUD_MIAP_Verification_Type] ,
           NULLIF(TRIM([STUD_MIAP_Other_Verification] ) , '') AS [STUD_MIAP_Other_Verification] ,
           NULLIF(TRIM([STUD_Bank_Sort_Code] ) , '') AS [STUD_Bank_Sort_Code] ,
           NULLIF(TRIM([STUD_Bank_AC_No] ) , '') AS [STUD_Bank_AC_No] ,
           [STUD_Bank_ISN] ,
           NULLIF(TRIM([STUD_Bank_Postcode] ) , '') AS [STUD_Bank_Postcode] ,
           NULLIF(TRIM([STUD_Bank_AC_Holders_Name] ) , '') AS [STUD_Bank_AC_Holders_Name] ,
           NULLIF(TRIM([STUD_Current_Tutor_Group] ) , '') AS [STUD_Current_Tutor_Group] ,
           NULLIF(TRIM([STUD_Current_PostCode] ) , '') AS [STUD_Current_PostCode] ,
           NULLIF(TRIM([STUD_Doctor_Name] ) , '') AS [STUD_Doctor_Name] ,
           NULLIF(TRIM([STUD_Doctor_Telephone] ) , '') AS [STUD_Doctor_Telephone] ,
           [STUD_ULN]  ,
           NULLIF(TRIM([STUD_College_Email_Address] ) , '') AS [STUD_College_Email_Address] ,
           [STUD_Date_Due_to_Leave_UK] ,
           [STUD_UK_Residence] ,
           NULLIF(TRIM([STUD_Parish] ) , '') AS [STUD_Parish] ,
           NULLIF(TRIM([STUD_Area] ) , '') AS [STUD_Area] ,
           [STUD_Bus_Pass] ,
           NULLIF(TRIM([STUD_Bus_Route] ) , '') AS [STUD_Bus_Route] ,
           [STUD_Eng_1st_Lang] ,
           NULLIF(TRIM([STUD_Language] ) , '') AS [STUD_Language] ,
           [STUD_High_Achiever] ,
           [STUD_Is_Staff] ,
           [STUD_Is_Staff_ISN] ,
           [STUD_Excluded] ,
           [STUD_RUI_3_no_contact] ,
           [STUD_RUI_1_courses] ,
           [STUD_RUI_2_surveys] ,
           [STUD_PMC_C1_post] ,
           [STUD_PMC_C2_phone] ,
           [STUD_PMC_C3_email] ,
           [STUD_Created_Date] ,
           NULLIF(TRIM([STUD_Created_User] ) , '') AS [STUD_Created_User] ,
           NULLIF(TRIM([STUD_Created_Prog] ) , '') AS [STUD_Created_Prog] ,
           [STUD_Modified_Date] ,
           NULLIF(TRIM([STUD_Modified_User] ) , '') AS [STUD_Modified_User] ,
           NULLIF(TRIM([STUD_Modified_Prog] ) , '') AS [STUD_Modified_Prog] ,
           [STUD_OK_to_use_Image] ,
           NULLIF(TRIM([STUD_Sexual_Orientation] ) , '') AS [STUD_Sexual_Orientation] ,
           NULLIF(TRIM([STUD_Gender_Identity] ) , '') AS [STUD_Gender_Identity] ,
           [STUD_Visa_Proof_Produced] ,
           [STUD_Visa_Proof_Produced_Date] ,
           NULLIF(TRIM([STUD_Visa_Proof_Produced_Details] ) , '') AS [STUD_Visa_Proof_Produced_Details] ,
           NULLIF(TRIM([STUD_Visa_Type] ) , '') AS [STUD_Visa_Type] ,
           [STUD_Visa_Expiry_Date] ,
           [STUD_Visa_Letter_Issued] ,
           [STUD_Asylum_Seeker] ,
           [STUD_Refugee] ,
           [STUD_Entered_UK_for_Education] ,
           [STUD_Restrictions_on_Stay] ,
           NULLIF(TRIM([STUD_Add_To_Portal_Title_Bar] ) , '') AS [STUD_Add_To_Portal_Title_Bar] ,
           [STUD_RUI_5] ,
           NULLIF(TRIM([STUD_Visa_Reference]) , '') AS  [STUD_Visa_Reference],
           NULLIF(TRIM([STUD_Visa_Note] ) , '') AS [STUD_Visa_Note] ,
           [STUD_FA_Bank_ISN] ,
           NULLIF(TRIM([STUD_FA_Bank_Sort_Code] ) , '') AS [STUD_FA_Bank_Sort_Code] ,
           NULLIF(TRIM([STUD_FA_Bank_AC_No] ) , '') AS [STUD_FA_Bank_AC_No] ,
           NULLIF(TRIM([STUD_FA_Bank_AC_Holders_Name]) , '') AS  [STUD_FA_Bank_AC_Holders_Name],
           NULLIF(TRIM([STUD_Marital_Status] ) , '') AS [STUD_Marital_Status] ,
           NULLIF(TRIM([STUD_Country_of_Birth] ) , '') AS [STUD_Country_of_Birth] ,
           NULLIF(TRIM([STUD_On_Supervision] ) , '') AS [STUD_On_Supervision] ,
           [STUD_S_IraqDEAS] ,
           [STUD_S_Pending_SCN] ,
           NULLIF(TRIM([STUD_Primary_LLDDCode] ) , '') AS [STUD_Primary_LLDDCode] ,
           NULLIF(TRIM([STUD_A2C_Language] ) , '') AS [STUD_A2C_Language] ,
           NULLIF(TRIM([STUD_Signature_Filename] ) , '') AS [STUD_Signature_Filename] ,
           [STUD_S_ILA_Expiry_Date] ,
           [STUD_Date_Of_Death] ,
           [STUD_S_SQA_Exception] ,
           NULLIF(TRIM([STUD_S_SQA_VID] ) , '') AS [STUD_S_SQA_VID] ,
           [STUD_S_SQA_Registration_Date] ,
           NULLIF(TRIM([STUD_FA_Bank_AC_Ref] ) , '') AS [STUD_FA_Bank_AC_Ref] ,
           NULLIF(TRIM([STUD_Bank_AC_Ref] ) , '') AS [STUD_Bank_AC_Ref] ,
           [STUD_Anonymised] ,
           NULLIF(TRIM([STUD_Quarantine_Status] ) , '') AS [STUD_Quarantine_Status] ,
           [STUD_KeycloakID] ,
           NULLIF(TRIM([STUD_Preferred_Surname] ) , '') AS [STUD_Preferred_Surname] ,
           [STUD_Exclude_From_Balancing] ,
           NULLIF(TRIM([STUD_Corresp_Preference] ) , '') AS [STUD_Corresp_Preference] ,
           NULLIF(TRIM([STUD_HESA_ID] ) , '') AS [STUD_HESA_ID] ,
           NULLIF(TRIM([STUD_FEPUS_ID] ) , '') AS [STUD_FEPUS_ID] ,
           NULLIF(TRIM([STUD_PEV_PIN] ) , '') AS [STUD_PEV_PIN] ,
           NULLIF(TRIM([STUD_Photo_GUID_Filename] ) , '') AS [STUD_Photo_GUID_Filename]
    INTO #students
    FROM [NG].[dbo].[STUDstudent];

    MERGE [people].[Person] AS [p]
    USING #students AS [s]
        ON [s].[STUD_ISN] = [p].[StudentDBID]
    WHEN MATCHED
            AND (
                    [s].[STUD_Surname] != [p].[Surname]
                        OR [s].[STUD_Preferred_Surname] != [p].[PreferredSurname]
                        OR [s].[STUD_Former_Surname] != [p].[FormerSurname]
                        OR [s].[STUD_Forename_1] != [p].[Forename]
                        OR [s].[STUD_Forename_2] != [p].[MiddleNames]
                        OR [s].[STUD_Known_As] != [p].[PreferredForename]
                        OR [s].[STUD_DoB] != [p].[DoB]
                        OR [s].[STUD_Gender] != [p].[Gender]
                        OR [s].[STUD_Gender_Identity] != [p].[GenderIdentity]
                        OR [s].[STUD_Title] != [p].[Title]
                        OR [s].[STUD_Deceased] != [p].[Deceased]
                        OR [s].[STUD_Date_of_Death] != [p].[DeceasedDate]
                        OR [s].[STUD_Is_Staff_ISN] != [p].[StaffDBID]
                )
       THEN UPDATE SET
                            [Surname] = [s].[STUD_Surname] ,
                            [PreferredSurname] = [s].[STUD_Preferred_Surname] ,
                            [FormerSurname] = [s].[STUD_Former_Surname],
                            [Forename] = [s].[STUD_Forename_1] ,
                            [MiddleNames] = [s].[STUD_Forename_2] ,
                            [PreferredForename] = [s].[STUD_Known_As],
                            [DoB] = [s].[STUD_DoB] ,
                            [Gender] = [s].[STUD_Gender] ,
                            [GenderIdentity] = [s].[STUD_Gender_Identity] ,
                            [Title] = [s].[STUD_Title] ,
                            [Deceased] = [s].[STUD_Deceased],
                            [StaffDBID] = [s].[STUD_Is_Staff_ISN]
    WHEN NOT MATCHED
        THEN INSERT (
                        [Surname] ,
                        [PreferredSurname] ,
                        [FormerSurname] ,
                        [Forename] ,
                        [MiddleNames] ,
                        [PreferredForename] ,
                        [DoB] ,
                        [Gender] ,
                        [GenderIdentity] ,
                        [Title] ,
                        [Deceased] ,
                        [DeceasedDate] ,
                        [StudentDBID] ,
                        [StaffDBID])
             VALUES (
                        [s].[STUD_Surname] ,
                        [s].[STUD_Preferred_Surname] ,
                        [s].[STUD_Former_Surname] ,
                        [s].[STUD_Forename_1] ,
                        [s].[STUD_Forename_2] ,
                        [s].[STUD_Known_As]  ,
                        [s].[STUD_DOB] ,
                        [s].[STUD_Gender] ,
                        [s].[STUD_Gender_Identity]  ,
                        [s].[STUD_Title] ,
                        [s].[STUD_Deceased] ,
                        [s].[STUD_Date_of_Death] ,
                        [s].[STUD_ISN] ,
                        [s].[STuD_IS_Staff_ISN]
                    );

END

它可能会变得更有效率,但考虑到它将成为每晚任务的一部分,并且 运行 当人们不使用该系统时,它可以在大约 2 秒内处理大约 35000 条记录,所以它是“足够高效。