Convertir la date stockée en tant que VARCHAR en INT pour la comparer à Date stockée en tant que INT

J'utilise SQL Server 2014. Ma request est plutôt simple, je crois. J'ai une table contenant un champ contenant une valeur de date qui est stockée en tant que VARCHAR , et une autre table contenant un champ contenant une valeur de date qui est stockée en tant que INT .

La valeur de date dans le champ VARCHAR est stockée comme ceci: 2015M01
La valeur de données dans le champ INT est stockée comme ceci: 201501

J'ai besoin de comparer ces tables les unes contre les autres en utilisant EXCEPT . Mon process de pensée consistait à extraire ou à ajuster le "M" de la valeur VARCHAR et à voir si cela me permettrait de comparer les deux. Si quelqu'un a une meilleure idée, comme utiliser CAST pour changer les formats de date ou quelque chose, n'hésitez pas à suggérer cela aussi.

Je suis également préoccupé par le fait que même l'extraction du "M" de VARCHAR peut empêcher la comparaison puisque l'un rest VARCHAR et l'autre INT . Si possible grâce à une requête T-SQL à convertir à la volée, ce serait également un excellent conseil. 🙂

Puisque vous dites que vous avez déjà la requête et utilisez EXCEPT , vous pouvez simplement modifier la définition de ce champ "date" dans la requête contenant la valeur VARCHAR afin qu'elle corresponde au format INT de l'autre requête. Par exemple:

 SELECT Field1, CONVERT(INT, REPLACE(VarcharDateField, 'M', '')) AS [DateField], Field3 FROM TableA EXCEPT SELECT Field1, IntDateField, Field3 FROM TableB 

Cependant, bien que je réalise que cela pourrait ne pas être réalisable, votre meilleure option, si vous pouvez y arriver, serait de changer la façon dont datatables de la table avec le champ VARCHAR sont stockées pour qu'il soit réellement un INT dans le même format comme la table avec datatables déjà stockées comme INT . Ensuite, vous n'auriez pas à vous soucier de situations comme celle-ci.

Sens:

  • Ajoutez un champ INT à la table avec le champ VARCHAR .
  • Effectuez une mise à jour de cette table, en définissant le champ INT sur la valeur de string avec le M supprimé.
  • Mettez à jour toutes les procédures stockées INSERT et / ou UPDATE utilisées par des services externes (application, ETL, etc.) pour faire cette même logique de suppression M.Vous n'avez alors pas besoin de modifier le code d'application INSERT et UPDATE. Vous n'avez même pas besoin de dire à quelqu'un que vous avez fait cela.
  • Mettez à jour toutes les procédures stockées SELECT / SELECT utilisées par des services externes (app, ETL, etc) pour faire la logique inverse: convertir l' INT en VARCHAR et append le M à la sortie. Ensuite, vous n'avez pas besoin de modifier un code d'application qui obtient des données de la database. Vous n'avez même pas besoin de dire à quelqu'un que vous avez fait cela.

C'est l'une des nombreuses raisons pour lesquelles avoir une API de procédure stockée dans votre database est très pratique. Je suppose qu'un ORM peut juste être reconstruit, mais vous devez encore recomstackr, même si toutes les references de code sont automatiquement mises à jour. Mais faire un changement de type de données (ou même déplacer un champ vers une table différente, ou même replace un champ avec une simple instruction CASE ) "en coulisses" et le masquer afin que tout code hors de votre contrôle ne sache pas qu'un changement arrivé, pas aussi difficile que la plupart des gens pourraient penser. J'ai effectué toutes ces opérations (changement de type de données, déplacement d'un champ vers une autre table, rlocation d'un champ par une logique simple, etc.) et il vous achète beaucoup de time jusqu'à ce que le code de l'application puisse être mis à jour. Cela pourrait être une autre équipe qui gère cela. Peut-être que leur calendar ne permettra pas de faire des changements dans ce domaine (plus les tests) pendant 3 mois. D'accord. Il sera là à les attendre quand ils seront prêts. Tout s'il y a plusieurs zones à mettre à jour, alors elles peuvent être faites une à la fois. Vous pouvez même créer de nouvelles procédures stockées à exécuter en parallèle pour que tout code d'application mis à jour possède le type de données INT approprié en tant que paramètre d'input. Et une fois que toutes les references à la valeur VARCHAR ont disparu, supprimez les versions d'origine de ces procédures stockées.

REPLACE la string puis CONVERT en entier

 SELECT A.*, B.* FROM TableA A INNER JOIN (SELECT intField FROM TableB ) as B ON CONVERT(INT, REPLACE(A.varcharField, 'M', '')) = B.intField 

Si vous voulez tout dans la première table qui n'est pas dans la seconde, vous pourriez envisager quelque chose comme ceci:

 select t1.* from t1 where not exists (select 1 from t2 where cast(replace(t1.varcharfield, 'M', '') as int) = t2.intfield ); 

Cela devrait être assez proche de l' except pour vos fins.

Je devrais append que vous pourriez avoir besoin d'inclure d'autres colonnes dans l'instruction where . Cependant, la question ne mentionne qu'une colonne, donc je ne sais pas ce que c'est.

Vous pouvez créer une vue persistante sur la table avec la colonne char, avec une colonne calculée où le M est supprimé. Ensuite, vous pouvez JOIN la vue à la table contenant la colonne INT .

 CREATE VIEW dbo.PersistedView WITH SCHEMA_BINDING AS SELECT ConvertedDateCol = CONVERT(INT, REPLACE(VarcharCol, 'M', '')) --, other columns including the PK, etc FROM dbo.TablewithCharColumn; CREATE CLUSTERED INDEX IX_PersistedView ON dbo.PersistedView(<the PK column>); SELECT * FROM dbo.PersistedView pv INNER JOIN dbo.TableWithIntColumn ic ON pv.ConvertedDateCol = ic.IntDateCol; 

Si vous fournissez les détails réels des deux arrays, je modifierai ma réponse pour la rendre plus claire.

Une vue persistante avec une colonne calculée fonctionnera beaucoup mieux sur l' SELECT où vous joignez les deux colonnes par rapport à faire le CONVERT et REPLACE chaque fois que vous exécutez l' SELECT .

Toutefois, une vue persistante ralentira légèrement les insertions dans les tables sous-jacentes et vous empêchera d'apporter des modifications DDL aux tables sous-jacentes.

Si vous ne souhaitez pas conserver les valeurs via une vue liée au schéma, vous pouvez créer une colonne calculée non persistante sur la table elle-même, puis créer un index non clusterisé sur cette colonne. Si vous utilisez la colonne calculée dans les clauses WHERE ou JOIN , vous pouvez en tirer un avantage.

A titre d'exemple:

 CREATE TABLE dbo.PCT ( PCT_ID INT NOT NULL CONSTRAINT PK_PCT PRIMARY KEY CLUSTERED IDENTITY(1,1) , SomeChar VARCHAR(50) NOT NULL , SomeCharToInt AS CONVERT(INT, REPLACE(SomeChar, 'M', '')) ); CREATE INDEX IX_PCT_SomeCharToInt ON dbo.PCT(SomeCharToInt); INSERT INTO dbo.PCT(SomeChar) VALUES ('2015M08'); SELECT SomeCharToInt FROM dbo.PCT; 

Résultats:

entrez la description de l'image ici