J'ai une colonne avec des lettres. Je veux diviser cette colonne en morceaux de trois. De quel code SQL pour Microsoft aurais-je besoin? J'ai lu `` diviser mon caractère spécial '' mais je ne sais pas comment créer une division par valeur où la division n'est pas non plus limitée au nombre de colonnes.
3 Réponses :
Vous pouvez faire:
select t.*, substring(col, 1, 3), substring(col, 4, 3), substring(col, 7, 3) from table t
Si vous voulez vraiment faire cela de manière dynamique, comme indiqué dans la question, et que vous avez une requête qui crée autant de colonnes que nécessaire, alors vous avez besoin de SQL dynamique.
Voici une solution qui utilise un CTE récusif pour générer la chaîne de requête.
-- debug | sql | | :---------------------------------------------------------------------------------------------------------------------------------- | | select substring(code, 1, 3) col1, substring(code, 4, 3) col2, substring(code, 7, 3) col3, substring(code, 10, 3) col4 from mytable | -- results col1 | col2 | col3 | col4 :--- | :--- | :--- | :--- ABC | DEF | GHI | XYZ | ABC | | JKL | MNO | PQR | STU ABC | DEF | |
L'ancre de la requête récursive calcule la longueur de la chaîne la plus longue dans la colonne code
. Ensuite, la partie récursive génère une série d'expressions substring ()
pour chaque morceau de 3 caractères, avec des noms de colonnes dynamiques comme col1
, col2
et bientôt. Vous pouvez ensuite (déboguer et) exécuter cette chaîne de requête.
declare @sql nvarchar(max); with cte as ( select 1 pos, cast('substring(code, 1, 3) col1' as nvarchar(max)) q, max(len(code)) max_pos from mytable union all select pos + 1, cast( q + ', substring(code, ' + cast(pos * 3 + 1 as nvarchar(3)) + ', 3) col' + cast(pos + 1 as nvarchar(3)) as nvarchar(max)), max_pos from cte where pos < max_pos / 3 ) select @sql = N'select ' + q + ' from mytable' from cte where len(q) = (select max(len(q)) from cte); select @sql sql; EXEC sp_executesql @sql;
Essayez-le comme ceci, qui ne nécessite aucun SQL générique (tant que vous pouvez spécifier un nombre maximum de colonnes):
Nous devons d'abord définir un scénario de maquette pour simuler votre issue
SELECT p.* FROM ( SELECT t.ID ,CONCAT('Col',A.Nmbr) AS ColumnName ,SUBSTRING(t.YourString,(A.Nmbr-1)*@ChunkLength + 1,@ChunkLength) AS Chunk FROM @tbl t CROSS APPLY ( SELECT TOP((LEN(t.YourString)+(@ChunkLength-1))/@ChunkLength) ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values ) A(Nmbr) ) src PIVOT ( MAX(Chunk) FOR ColumnName IN(Col1,Col2,Col3,Col4,Col5,Col6 /*add the maximum column count here*/) ) p;
- Nous pouvons définir la longueur du morceau de manière générique. Essayez-le avec d'autres valeurs ...
DECLARE @ChunkLength INT=3;
--La requête
DECLARE @tbl TABLE(ID INT IDENTITY, YourString VARCHAR(100)); INSERT INTO @tbl VALUES ('AB') ,('ABC') ,('ABCDEFGHI') ,('XYZABC') ,('JKLMNOPQRSTU') ,('ABCDEF');
L'idée en bref: p >
APPLY
, nous pouvons créer un décompte par ligne . Cela renverra plusieurs lignes par chaîne d'entrée. Le nombre de lignes est défini par la clause TOP calculée. SUBSTRING ()
. PIVOT
pour renvoyer ceci sous forme de liste horizontale. Un indice sur les ensembles de résultats génériques:
Cela pourrait être une sorte de religion , mais - du moins à mon avis - je préférerais un fix avec beaucoup de colonnes vides, plutôt qu'un ensemble défini de manière générique . Le consommateur doit connaître le format du résultat à l'avance ...
Vous pouvez utiliser exactement la même requête qu'une instruction SQL créée dynamiquement. La seule chose que vous auriez besoin de changer est la liste réelle des noms de colonnes dans la clause IN
du PIVOT.