รับการเกิดขึ้นครั้งที่ 2 หรือ 3 ของค่าในสตริงที่มีการคั่น


11

ฉันมีตารางต่อไปนี้:

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

ฉันกำลังคิดที่จะทำให้คำสั่ง SQL ของฉันง่ายขึ้นดังต่อไปนี้:

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

ดังนั้นเมื่อฉันทำการ SQL มันจะให้ผลลัพธ์ต่อไปนี้กับฉัน:

==========================================================
|  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     |
==========================================================

มีวิธีใดที่จะทำให้ SQL ของฉันง่ายขึ้น?

คำตอบ:


25

คุณสามารถใช้cross applyและพารามิเตอร์ที่สามของcharindexเพื่อรับตำแหน่งขีดล่าง

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)

ผลลัพธ์:

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

อัปเดต:ใช้ตารางของคุณแบบสอบถามจะมีลักษณะดังนี้:

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

อัปเดต 2:

หากคุณทราบว่าค่าของคุณไม่เคยมีระยะเวลา.และมันมักจะเป็นชื่อสี่ส่วนหนึ่งที่คุณสามารถใช้parsename

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

1

PARSENAME ถูกกล่าวถึงเป็นวิธีแก้ปัญหาหากสตริงไม่มีจุด ถ้ามันใช้การปรับเปลี่ยนนี้เพื่อเปลี่ยนจุดเป็นอย่างอื่นแล้วแยกค่าแล้วใส่จุดกลับ

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

1

คุณสามารถใช้ UDF ต่อไปนี้ (ฟังก์ชั่นอินไลน์มากกว่าสเกลาร์)

 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 

วิธีใช้:

 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.