Ermittelt das 2. oder 3. Vorkommen eines Werts in einer durch Trennzeichen getrennten Zeichenfolge

11

Ich habe folgende Tabelle:

==========================================================
|  Name_Level_Class_Section   |   Phone Num              |
==========================================================
|  Jacky_1_B2_23              |  1122554455              |
|  Johnhy_1_B2_24             |  1122554455              |
|  Peter_2_A5_3               |  1122554455              |
==========================================================

Ich denke daran, meine SQL-Anweisung wie folgt zu vereinfachen:

select 
    *, 
    substring(Name_Level_Class_Section, 
              CHARINDEX('_',Name_Level_Class_Section,
              (CHARINDEX('_', Name_Level_Class_Section) + 1)) + 1, 
      CHARINDEX('_',Name_Level_Class_Section,
     (CHARINDEX('_',Name_Level_Class_Section,
     (CHARINDEX('_',Name_Level_Class_Section)+1))+1))-    
      CHARINDEX('_',Name_Level_Class_Section,
     (CHARINDEX('_',Name_Level_Class_Section)+1))) as CLA 
from 
    Bookings 
order by 
    CLA asc, Name_Level_Class_Section asc

Wenn ich SQL ausführe, erhalte ich folgendes Ergebnis:

==========================================================
|  Name_Level_Class_Section   |  Phone Num     |  CLA    |
==========================================================
|  Jacky_1_B2_23              |  1122554455    |  B2     |
|  Johnhy_1_B2_24             |  1122554455    |  B2     |
|  Peter_2_A5_3               |  1122554455    |  A5     |
==========================================================

Gibt es eine Möglichkeit, mein SQL zu vereinfachen?

Jack
quelle

Antworten:

24

Sie können cross applyden dritten Parameter von verwenden charindex, um die Position der Unterstriche zu ermitteln.

declare @T table
(
  Name_Level_Class_Section varchar(25)
)

insert into @T values
('Jacky_1_B2_23'),
('Johnhy_1_B2_24'),
('Peter_2_A5_3')

select substring(Name_Level_Class_Section, P2.Pos + 1, P3.Pos - P2.Pos - 1)
from @T
  cross apply (select (charindex('_', Name_Level_Class_Section))) as P1(Pos)
  cross apply (select (charindex('_', Name_Level_Class_Section, P1.Pos+1))) as P2(Pos)
  cross apply (select (charindex('_', Name_Level_Class_Section, P2.Pos+1))) as P3(Pos)

Ergebnis:

-------------------------
B2
B2
A5

Update: Mit Ihrer Tabelle würde die Abfrage folgendermaßen aussehen:

select *, 
       substring(Name_Level_Class_Section, P2.Pos + 1, P3.Pos - P2.Pos - 1) as CLA
from Bookings
  cross apply (select (charindex('_', Name_Level_Class_Section))) as P1(Pos)
  cross apply (select (charindex('_', Name_Level_Class_Section, P1.Pos+1))) as P2(Pos)
  cross apply (select (charindex('_', Name_Level_Class_Section, P2.Pos+1))) as P3(Pos)
order by CLA asc,
         Name_Level_Class_Section asc

Update 2:

Wenn Sie sicher sind, dass Ihr Wert niemals einen Punkt enthält .und dass es sich immer um einen vierteiligen Namen handelt, können Sie den Parsenamen verwenden .

select *, 
       parsename(replace(Name_Level_Class_Section, '_', '.'), 2) as CLA
from Bookings
order by CLA asc,
         Name_Level_Class_Section asc
Mikael Eriksson
quelle
1

PARSENAME wurde als Lösung erwähnt, wenn die Zeichenfolge keinen Punkt enthielt. Wenn diese Änderung verwendet wird, um die Perioden in etwas anderes zu ändern, analysieren Sie den Wert und setzen Sie die Perioden zurück

  Select REPLACE(PARSENAME(REPLACE(REPLACE('Jacky_1_B2.00_23','.','~'), '_', '.'), 2),'~','.')
SSDiver2112
quelle
1

Sie können die folgende UDF verwenden (Inline-Funktion anstelle von Skalar)

 CREATE FUNCTION dbo.INSTR 
 (
 @str VARCHAR(8000),
 @Substr VARCHAR(1000),
 @start INT ,
 @Occurance INT
 )
 RETURNS TABLE 
 AS 
 RETURN

WITH Tally (n) AS
(
    SELECT TOP (LEN(@str)) ROW_NUMBER()  OVER (ORDER BY (SELECT NULL)) 
    FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0)) a(n)
    CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
    CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
    CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(n)
)

, Find_N_STR as
(
   SELECT 
    CASE WHEN DENSE_RANK() OVER(PARTITION BY @Substr ORDER BY (CHARINDEX(@Substr ,@STR ,N))) = @Occurance 
     THEN MAX(N-@start +1) OVER (PARTITION BY CHARINDEX(@Substr ,@STR ,N) ) 
     ELSE 0 
     END [Loc]
FROM Tally
WHERE CHARINDEX(@Substr ,@STR ,N) > 0 
)

SELECT Loc= MAX(Loc) 
FROM Find_N_STR
WHERE Loc > 0 

Wie benutzt man:

 declare @T table 
 (
 Name_Level_Class_Section varchar(25)
 )
 insert into @T values
  ('Jacky_1_B2_23'),
  ('Johnhy_1_B2_24'),
  ('Peter_2_A5_3')

  select t.Name_Level_Class_Section  , l.Loc
  from @t t
  cross apply  dbo.INSTR (t.Name_Level_Class_Section, '_',1,2) l
hkravitz
quelle