1

I want to find the difference between two strings and string manipulation isn't my strong suit. I have the following code.

SELECT 
T0.[Code], 
T0.[U_CardCode],
T1.CardName, 
T0.[U_Subj], 
CASE WHEN T0.[U_SubStatus] = 'o' THEN 'Open' ELSE 'Closed' END AS 'Status', 
CONCAT(T0.[U_Every],' ' ,CASE WHEN T0.[U_Unit] = 3 THEN 'Months' ELSE 'Year' END) AS 'Frequency', 
T0.[U_FDate], 
T0.[U_CatCode], 
T0.[U_UserField1] AS 'Expected Hours', 
T0.[U_Rem],
(SELECT TOP 1 (len(CAST(A.U_ACEqCodes AS VARCHAR(MAX))) - len(replace(CAST(A.U_ACEqCodes AS VARCHAR(MAX)), ';', ''))) + 1 FROM [dbo].[@SWA_CT_SUBSCR_PLTPL]  A INNER JOIN [dbo].[@SWA_CT_SUBSCR]  B ON B.Code = A.U_SubscriptionCode WHERE B.[U_CardCode] = T0.U_CardCode AND CONVERT(NVARCHAR(MAX),A.[U_ACEqCodes]) <> '') AS 'QTY A',

(SELECT TOP 1 A.[U_ACEqCodes] FROM [dbo].[@SWA_CT_SUBSCR_PLTPL]  A INNER JOIN [dbo].[@SWA_CT_SUBSCR]  B ON B.Code = A.U_SubscriptionCode WHERE B.[U_CardCode] = T0.U_CardCode AND CONVERT(NVARCHAR(MAX),A.[U_ACEqCodes]) <> '') AS 'Equipment in Subscription',
 
(SELECT count (A.insID) FROM OINS A WHERE A.customer = T0.U_CardCode AND (A.ItemName NOT LIKE '%%ENVIRO%%' AND A.ItemName NOT LIKE '%%Heat Seal%%' AND A.ItemName NOT LIKE '%%Printer%%' AND A.ItemName NOT LIKE '%%Commercial%%')) AS 'QTY B',

stuff((select '; '  + CAST(r.insID AS VARCHAR(100))
 from OINS r  where r.customer = T0.U_CardCode AND (r.ItemName NOT LIKE '%%ENVIRO%%' AND r.ItemName NOT LIKE '%%Heat Seal%%' AND r.ItemName NOT LIKE '%%Printer%%' AND r.ItemName NOT LIKE '%%Commercial%%')
  FOR XML PATH('')), 1, 2, '') AS [Equipment from Cards],

T0.[U_Total], 

CASE WHEN T2.GroupName NOT IN ('Customers','Retail') THEN ((SELECT CAST(count(A.insID) AS DECIMAL) FROM OINS A WHERE A.customer = T0.U_CardCode AND (A.ItemName NOT LIKE '%%ENVIRO%%' AND A.ItemName NOT LIKE '%%Heat Seal%%' AND A.ItemName NOT LIKE '%%Printer%%' AND A.ItemName NOT LIKE '%%Commercial%%')) * 1.5 * 112) + 1 * 112
ELSE
((SELECT CAST(count(A.insID) AS DECIMAL) FROM OINS A WHERE A.customer = T0.U_CardCode AND (A.ItemName NOT LIKE '%%ENVIRO%%' AND A.ItemName NOT LIKE '%%Heat Seal%%' AND A.ItemName NOT LIKE '%%Printer%%' AND A.ItemName NOT LIKE '%%Commercial%%')) * 1.5 * 140) + 1 * 140
END AS 'Theoretical Charge'

FROM [dbo].[@SWA_CT_SUBSCR]  T0 
INNER JOIN OCRD T1 ON T1.CardCode = T0.U_CardCode
INNER JOIN OCRG T2 ON T1.GroupCode = T2.GroupCode

Which gives the following type of output

enter image description here

As you can see, both columns have different equipment ID's, what i would like to do is compare both strings and output the difference between them in a following column.

Here is how the code looks with just both columns I am trying to compare;

SELECT 

(SELECT TOP 1 A.[U_ACEqCodes] 
FROM [dbo].[@SWA_CT_SUBSCR_PLTPL]  A 
INNER JOIN [dbo].[@SWA_CT_SUBSCR]  B ON B.Code = A.U_SubscriptionCode 
WHERE B.[U_CardCode] = T0.U_CardCode 
AND CONVERT(NVARCHAR(MAX),A.[U_ACEqCodes]) <> '') AS 'Equipment in Subscription',
 
stuff((select '; '  + CAST(r.insID AS VARCHAR(10))
from OINS r  
where r.customer = T0.U_CardCode AND 
(r.ItemName NOT LIKE '%%ENVIRO%%' AND 
r.ItemName NOT LIKE '%%Heat Seal%%' AND 
r.ItemName NOT LIKE '%%Printer%%' AND 
r.ItemName NOT LIKE '%%Commercial%%')
FOR XML PATH('')), 1, 2, '') AS [Equipment from Cards]

FROM [dbo].[@SWA_CT_SUBSCR]  T0 
INNER JOIN OCRD T1 ON T1.CardCode = T0.U_CardCode
INNER JOIN OCRG T2 ON T1.GroupCode = T2.GroupCode

An example of what I am trying to achieve is;

String 1 = 7849;7985;8044;8253;8254;16733 String 2 = 7849; 16733; 8044; 7985

Outcome = 8253;8254

Any help is appreciated. My code isn't really the most optimal either, if there is a more optimal way of writing it I would be happy to learn.

NickW
  • 8,430
  • 2
  • 6
  • 19
Nick Jones
  • 93
  • 8
  • Please provide a minimum reproducible example - it looks like 90% of thar SQL is not relevant to your question. What do you mean by the difference between 2 strings? Please provide some sample data and the result you expect based on that sample data – NickW Jun 17 '21 at 07:46
  • I would create a table-valued-function that splits the column into a temp table on the ; delimiter, then compare the 2 temporary tables with joins or a where clause. – Praxiom Jun 17 '21 at 09:33
  • 1
    Hi @NickW - I have added what you requested. I dont know how to do this sawsine. – Nick Jones Jun 17 '21 at 23:46
  • in the where cause for the first subquery, could you just add Where A.[U_ACEqCodes] NOT IN ( Select all the bits from the second column subquery) ? just freeballin' here. Sorry! – Praxiom Jul 02 '21 at 13:57

1 Answers1

1

First i Would Create a table Valued Function, which will split a string (or result of subquery) into individual values based on the supplied delimiter:

USE [maintanence]
GO
/****** Object:  UserDefinedFunction [dbo].[StringListToTable]    
Script 
Date: 05/07/2021 07:09:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[StringListToTable] (@list  nvarchar(MAX),
                                @delim nvarchar(10))
   RETURNS @tbl TABLE (listpos int NOT NULL IDENTITY(1,1),
                       n       int NULL) AS
BEGIN
   DECLARE @pos       int = 1,
           @nextpos   int = 1,
           @valuelen  int,
           @delimlen  int = datalength(@delim) / 2

   WHILE @nextpos > 0
   BEGIN
          SELECT @nextpos = charindex(@delim COLLATE Czech_BIN2, @list, @pos)
          SELECT @valuelen = CASE WHEN @nextpos > 0 THEN @n

extpos
                              ELSE len(@list) + 1
                         END - @pos
      INSERT @tbl (n)
         VALUES (convert(int, nullif(substring(@list, @pos, @valuelen), '')))
      SELECT @pos = @nextpos + @delimlen
   END
   RETURN
END

(thanks to this excellent article: https://www.sommarskog.se/arrays-in-sql.html )

Then I would use the function as follows (For clarity I have omitted your where clauses and only selected one column)

select 

  STUFF((SELECT ';' + CAST(x.equip AS VARCHAR(MAX))
     FROM (select n [equip] from StringListToTable(
                (select [Equip] FROM [Maintenance].[dbo].[testing]  ),';') 
                    where n not in (select cards from [Maintenance].[dbo].[Testing2] ) ) x
     FOR XML PATH('')),1,1,'') [Difference]

test tables: enter image description here enter image description here

Result: enter image description here

Praxiom
  • 578
  • 1
  • 8
  • 21
  • Hi Sawsine, thanks for your answer. Unfortunately the 'Equipment from Subscription' (U_ACEqCodes) column is treated as one complete string instead of seperate id's so this does not work. It just returns the whole string again. – Nick Jones Jul 05 '21 at 03:52
  • 1
    Hi Nick, I have amended my answer, hope it helps. – Praxiom Jul 05 '21 at 06:41
  • Hi nick, did you have any luck with this? – Praxiom Jul 09 '21 at 12:55