Dans \/blogs\/tilting\/2016\/09\/27\/performance-at-a-price-file-geodatabases-and-sql-support?sr=search&searchId=c3a45d0d-24f6-481b-bcf7-cfc7493b25fc&searchIndex=0<\/A>, je souligne le compromis du support SQL qu'Esri a fait lors du développement de la file geodatabase (FGDB) comme remplacement de la personal geodatabase (PGDB). Dans ce billet, plusieurs liens sont fournis pour ceux qui souhaitent en savoir plus sur le support SQL dans les file geodatabases. Bien qu'il y ait beaucoup de chevauchement dans le contenu entre les différentes sources\/liens, il y a aussi des déclarations importantes qui n'existent que dans un endroit ou un autre, et le savoir peut être important lors du dépannage d'erreurs ou pour comprendre des résultats erronés provenant de données stockées dans des file geodatabases.<\/P><\/P>Un domaine où les utilisateurs peuvent se mettre en difficulté avec les file geodatabases et SQL est la condition ou opérateur EXISTS. En regardant la référence SQL (FileGDB_SQL.htm) dans l'API File Geodatabase ( @Esri Downloads <\/A>) ou la référence SQL pour les expressions de requête utilisées dans ArcGIS<\/A>:<\/P>[NOT] EXISTS<\/P><\/TD>Renvoie TRUE si la sous-requête renvoie au moins un enregistrement ; sinon, elle renvoie FALSE. Par exemple, cette expression renvoie TRUE si le champ OBJECTID contient une valeur de 50 :<\/P>EXISTS (SELECT * FROM parcels WHERE "OBJECTID" = 50)<\/PRE>EXISTS est pris en charge uniquement dans les file, personal et ArcSDE geodatabases.<\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Voyant que SQL EXISTS est pris en charge dans la file geodatabase, comment quelqu'un peut-il se mettre en difficulté en l'utilisant ? Malheureusement, c'est plus facile que vous ne le pensez, et la réponse réside dans les sous-requêtes corrélées.<\/P><\/P>Les sous-requêtes corrélées sont assez courantes lorsqu'on travaille avec EXISTS, tellement courantes en fait que la documentation Microsoft EXISTS (Transact-SQL)<\/A> et la documentation Oracle Condition EXISTS <\/A> utilisent toutes deux une sous-requête corrélée dans amp au moins amp un exemple de code. Au plus simple, une sous-requête corrélée est une sous-requête qui se rapporte à une ou plusieurs tables dans la requête externe. La théorie et l'empirisme des sous-requêtes corrélées vont bien au-delà de ce billet de blog, mais je mentionnerai que les sous-requêtes corrélées ont certaines propriétés similaires à JOIN, ou du moins en apparence.<\/P><\/P>L'exemple suivant est tiré de Select Max value arcpy<\/A>, la même question GeoNet qui m'a amené à rechercher ce problème il y a plusieurs mois. Commençons par deux tables basiques (TableA et TableB), toutes deux ayant un champ texte et un champ entier, et l'une contenant un sous-ensemble d'enregistrements de l'autre table.<\/P><\/P><\/P>>><\/SPAN>><\/SPAN> fgdb =<\/SPAN> # chemin vers file geodatabase\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/> class="punctuation token">)<\/SPAN>:<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> table =<\/SPAN> arcpy.<\/SPAN>CreateTable_management(<\/SPAN>gdb, <\/SPAN>table_names[<\/SPAN>i-1<\/SPAN>]<\/SPAN>)<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> arcpy.<\/SPAN>AddField_management(<\/SPAN>table, <\/SPAN>"id"<\/SPAN>, <\/SPAN>"TEXT"<\/SPAN>)<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> arcpy.<\/SPAN>AddField_management(<\/Span>table, <\/Span>"version"<\/Span>, <\/Span>"LONG"<\/Span>)<\/Span> .<\/Span>.<\/Span>.<\/Span> avec arcpy.<\/Span>da.<\/Span>InsertCursor(<\/Span>table, <\/Span>("id") , "version") ) comme cur:... pour value dans values[: :i]: ...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; cur.insertRow(value)...& nbsp; & nbsp; & nbsp; & nbsp;...& nbsp; & nbsp; & nbsp; & nbsp; qry = (...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;"EXISTS (SELECT 1"...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;< spanclass= " stringtoken ">"& ; FROM TableB"</ span >.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& n b s p;< spanclass= " stringtoken ">" WHERE TableB.id = TableA.id"</ span >.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p;< spanclass= " stringtoken ">" AND TableB.version = TableA.version)"</ span > ).</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ;.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ; table_view = arcpy.MakeTableView_management(table, < spanclass =" stringtoken ">"table_view"</ span >, qry).... print arcpy.GetCount_management(table_view)... arcpy.Delete_management(table_view)0333>>> >>>>>>>>>>>>>>>>>>>></ SP > < SP an > < EM OJ I _ 21 > > < / SP > < SP a n > < EM OJ I _ 22 > > < / SP > < SP a n > < EM OJ I _ 23 > > < / SP > < SP a n > < EM OJ I _ 24 > > < / SP > < SP a n > < EM OJ I _ 25 > > < / SP > < SP a n > < EM OJ I _ 26 > > < / SP > < SP a n > < EM OJ I _ 27 > > < / SP > < SP a n > < EM OJ I _ 28 > > < / SP > < SP a n > < EM OJ I _ 29 > > < / SP > < SP a n > < EM OJ I _ 30 > > < / SP > < SP a n > < EM OJ I _ 31 > > < / SP > < SP a n > < EM OJ I _ 32 > > < / SP > < SP a n > < EM OJ I _ 33 >> </ Span ></ CODE ></ PRE ></ P ></ P ></ P >Le code d'exemple ci-dessus crée les deux tables de base dans une file geodatabase, personal geodatabase, enterprise geodatabase (j'ai utilisé SQL Server) et unGeoPackage. Le code crée ensuite une vue de table pour chacune des geodatabases en utilisant EXISTS avec une simple sous-requête corrélée pour sélectionner les enregistrements de TableA qui ont un id et une version correspondants dans TableB. La vue de table correcte est montrée dans la capture d'écran ci-dessus. On peut voir d'après les résultats du code qu'aucun enregistrement ne provient de la file geodatabase.Alors pourquoi la file geodatabase ne renvoie-t-elle aucun enregistrement ? Les sous-requêtes ne sont-elles pas prises en charge ? Étant donné que la documentation pour EXISTS mentionne les sous-requêtes, il semble qu'elles doivent être prises en charge, au moins dans une certaine mesure. Examinons de plus près la sectionSous-requêtes de laRéférence SQL pour les expressions de requête utilisées dans ArcGIS:
<\/P>
Un domaine où les utilisateurs peuvent se mettre en difficulté avec les file geodatabases et SQL est la condition ou opérateur EXISTS. En regardant la référence SQL (FileGDB_SQL.htm) dans l'API File Geodatabase (
[NOT] EXISTS<\/P><\/TD>Renvoie TRUE si la sous-requête renvoie au moins un enregistrement ; sinon, elle renvoie FALSE. Par exemple, cette expression renvoie TRUE si le champ OBJECTID contient une valeur de 50 :<\/P>EXISTS (SELECT * FROM parcels WHERE "OBJECTID" = 50)<\/PRE>EXISTS est pris en charge uniquement dans les file, personal et ArcSDE geodatabases.<\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Voyant que SQL EXISTS est pris en charge dans la file geodatabase, comment quelqu'un peut-il se mettre en difficulté en l'utilisant ? Malheureusement, c'est plus facile que vous ne le pensez, et la réponse réside dans les sous-requêtes corrélées.<\/P><\/P>Les sous-requêtes corrélées sont assez courantes lorsqu'on travaille avec EXISTS, tellement courantes en fait que la documentation Microsoft
[NOT] EXISTS<\/P><\/TD>
Renvoie TRUE si la sous-requête renvoie au moins un enregistrement ; sinon, elle renvoie FALSE. Par exemple, cette expression renvoie TRUE si le champ OBJECTID contient une valeur de 50 :<\/P>
EXISTS (SELECT * FROM parcels WHERE "OBJECTID" = 50)<\/PRE>EXISTS est pris en charge uniquement dans les file, personal et ArcSDE geodatabases.<\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Voyant que SQL EXISTS est pris en charge dans la file geodatabase, comment quelqu'un peut-il se mettre en difficulté en l'utilisant ? Malheureusement, c'est plus facile que vous ne le pensez, et la réponse réside dans les sous-requêtes corrélées.<\/P><\/P>Les sous-requêtes corrélées sont assez courantes lorsqu'on travaille avec EXISTS, tellement courantes en fait que la documentation Microsoft
L'exemple suivant est tiré de
>><\/SPAN>><\/SPAN> fgdb =<\/SPAN> # chemin vers file geodatabase\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/<\/> class="punctuation token">)<\/SPAN>:<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> table =<\/SPAN> arcpy.<\/SPAN>CreateTable_management(<\/SPAN>gdb, <\/SPAN>table_names[<\/SPAN>i-1<\/SPAN>]<\/SPAN>)<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> arcpy.<\/SPAN>AddField_management(<\/SPAN>table, <\/SPAN>"id"<\/SPAN>, <\/SPAN>"TEXT"<\/SPAN>)<\/SPAN>.<\/SPAN>.<\/SPAN>.<\/SPAN> arcpy.<\/SPAN>AddField_management(<\/Span>table, <\/Span>"version"<\/Span>, <\/Span>"LONG"<\/Span>)<\/Span> .<\/Span>.<\/Span>.<\/Span> avec arcpy.<\/Span>da.<\/Span>InsertCursor(<\/Span>table, <\/Span>("id") , "version") ) comme cur:... pour value dans values[: :i]: ...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; cur.insertRow(value)...& nbsp; & nbsp; & nbsp; & nbsp;...& nbsp; & nbsp; & nbsp; & nbsp; qry = (...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;"EXISTS (SELECT 1"...& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;< spanclass= " stringtoken ">"& ; FROM TableB"</ span >.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& nb sp ;& n b s p;< spanclass= " stringtoken ">" WHERE TableB.id = TableA.id"</ span >.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p ;& n b s p;< spanclass= " stringtoken ">" AND TableB.version = TableA.version)"</ span > ).</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ;.</ span >< spanclass= " punctuationtoken ">.</ span >< spanclass= " punctuationtoken ">.</ span >& n b s p ;& n b s p ; table_view = arcpy.MakeTableView_management(table, < spanclass =" stringtoken ">"table_view"</ span >, qry).... print arcpy.GetCount_management(table_view)... arcpy.Delete_management(table_view)0333>>> >>>>>>>>>>>>>>>>>>>></ SP > < SP an > < EM OJ I _ 21 > > < / SP > < SP a n > < EM OJ I _ 22 > > < / SP > < SP a n > < EM OJ I _ 23 > > < / SP > < SP a n > < EM OJ I _ 24 > > < / SP > < SP a n > < EM OJ I _ 25 > > < / SP > < SP a n > < EM OJ I _ 26 > > < / SP > < SP a n > < EM OJ I _ 27 > > < / SP > < SP a n > < EM OJ I _ 28 > > < / SP > < SP a n > < EM OJ I _ 29 > > < / SP > < SP a n > < EM OJ I _ 30 > > < / SP > < SP a n > < EM OJ I _ 31 > > < / SP > < SP a n > < EM OJ I _ 32 > > < / SP > < SP a n > < EM OJ I _ 33 >> </ Span ></ CODE ></ PRE ></ P ></ P ></ P >Le code d'exemple ci-dessus crée les deux tables de base dans une file geodatabase, personal geodatabase, enterprise geodatabase (j'ai utilisé SQL Server) et un
Sous-requêtesNote : <\/H5>Les couvertures, shapefiles et autres sources de données basées sur des fichiers non géodatabase ne prennent pas en charge les sous-requêtes. Les sous-requêtes effectuées sur des classes d'entités et tables ArcSDE versionnées ne retourneront pas les entités stockées dans les tables delta. Les géodatabases fichier offrent un support limité pour les sous-requêtes expliqué dans cette section, tandis que les géodatabases personnelles et ArcSDE offrent un support complet. Pour des informations sur l'ensemble complet des capacités de sous-requête des géodatabases personnelles et ArcSDE, référez-vous à la documentation de votre DBMS.<\/P><\/DIV><\/P><\/P><\/P><\/P>Une sous-requête est une requête imbriquée dans une autre requête. Elle peut être utilisée pour appliquer des fonctions prédicatives ou agrégées ou pour comparer des données avec des valeurs stockées dans une autre table....<\/P><\/BLOCKQUOTE><\/P>Le support des sous-requêtes dans les géodatabases fichier est limité aux éléments suivants :<\/P>Prédicat IN. Par exemple :<\/LI><\/UL>"COUNTRY_NAME" NOT IN (SELECT "COUNTRY_NAME" FROM indep_countries)<\/PRE>Sous-requêtes scalaires avec opérateurs de comparaison. Une sous-requête scalaire retourne une seule valeur. Par exemple :<\/LI><\/UL>"GDP2006" > (SELECT MAX("GDP2005") FROM countries)<\/PRE>Pour les géodatabases fichier, les fonctions d'ensemble AVG, COUNT, MIN, MAX et SUM ne peuvent être utilisées que dans des sous-requêtes scalaires.<\/SPAN><\/P>Prédicat EXISTS. Par exemple :<\/LI><\/UL>EXISTS (SELECT * FROM indep_countries WHERE "COUNTRY_NAME" = 'Mexico')<\/PRE><\/BLOCKQUOTE><\/P>La documentation indique un « support limité » pour les sous-requêtes, mais elle indique également que le prédicat EXISTS est pris en charge. Si les sous-requêtes ne posent pas problème, peut-être que ce sont les sous-requêtes corrélées qui posent problème. Après tout, aucun des exemples EXISTS dans toute la documentation n'utilise une sous-requête corrélée. Malheureusement, il ne reste que des suppositions car les sous-requêtes corrélées ne sont mentionnées explicitement dans aucune documentation de géodatabase fichier que je puisse trouver.<\/P><\/P>À partir de cet exemple simple, il est clair que la géodatabase fichier donne des résultats incorrects lorsqu'on utilise EXISTS avec des sous-requêtes corrélées. Ces résultats incorrects sont-ils un bug ou une limitation du support SQL dans la géodatabase fichier ? Même si l'on essaie d'argumenter pour cette dernière hypothèse, il y a toujours le problème que l'utilisateur obtienne des résultats incorrects au lieu d'un message d'erreur, ce qui devrait être le cas si les sous-requêtes corrélées ne sont pas prises en charge.<\/P><\/BODY><\/HTML>
File Geodatabase does not support correlated subqueries,
After publishing the blog post, I got to wondering how GeoPackages are handled. It turns out, they work just fine, i.e., one can create the tables and table view from a GeoPackage and get the correct results. I went ahead and updated the code to include using a GeoPackage.
lshipman-esristaff, thanks for the inside scoop. Do you have any idea if that recognition of response differences in geodatabases means that the documentation will be updated to be a bit more explicit, that there will be fixes (next version, patches, hotfixes) to allow SQL Correlated Subqueries to work in fGDB like they work in other data formats in the future, or is it just that this as far as it goes for the time? Thanks in advance.
I plan on updating the documentation Post 10.5. Support of SQL Correlated Subqueries is not currently planned for the fGDB, but if a persuasive business case is submitted we will consider it.
Although my blog post example involved two tables, one of our most common uses for correlated subqueries is actually self-correlated subqueries:
<SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> fgdb <SPAN class="operator token">=</SPAN> <SPAN class="comment token"># path to file geodatabase</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> pgdb <SPAN class="operator token">=</SPAN> <SPAN class="comment token"># path to personal geodatabase</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> egdb <SPAN class="operator token">=</SPAN> <SPAN class="comment token"># path to enterprise geodatabase, SQL Server used in example</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> gpkg <SPAN class="operator token">=</SPAN> <SPAN class="comment token"># path to GeoPackage</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> gdbs <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">(</SPAN>fgdb<SPAN class="punctuation token">,</SPAN> pgdb<SPAN class="punctuation token">,</SPAN> egdb<SPAN class="punctuation token">,</SPAN> gpkg<SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> values <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">"A"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"A"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"B"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"B"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"C"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"C"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">3</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"D"</SPAN><SPAN class="punctuation token">,</SPAN> None<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"E"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> table_name <SPAN class="operator token">=</SPAN> <SPAN class="string token">"TableA"</SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="keyword token">for</SPAN> gdb <SPAN class="keyword token">in</SPAN> gdbs<SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> table <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>CreateTable_management<SPAN class="punctuation token">(</SPAN>gdb<SPAN class="punctuation token">,</SPAN> table_name<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>AddField_management<SPAN class="punctuation token">(</SPAN>table<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"id"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"TEXT"</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>AddField_management<SPAN class="punctuation token">(</SPAN>table<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"version"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"LONG"</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="keyword token">with</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>da<SPAN class="punctuation token">.</SPAN>InsertCursor<SPAN class="punctuation token">(</SPAN>table<SPAN class="punctuation token">,</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"id"</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"version"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="keyword token">as</SPAN> cur<SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="keyword token">for</SPAN> value <SPAN class="keyword token">in</SPAN> values<SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> cur<SPAN class="punctuation token">.</SPAN>insertRow<SPAN class="punctuation token">(</SPAN>value<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> qry <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="string token">"NOT EXISTS (SELECT 1"</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="string token">" FROM TableA a"</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="string token">" WHERE TableA.id = a.id"</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="string token">" AND TableA.version < a.version)"</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> table_view <SPAN class="operator token">=</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>MakeTableView_management<SPAN class="punctuation token">(</SPAN>table<SPAN class="punctuation token">,</SPAN> <SPAN class="string token">"table_view"</SPAN><SPAN class="punctuation token">,</SPAN> qry<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>TableToTable_conversion<SPAN class="punctuation token">(</SPAN>table_view<SPAN class="punctuation token">,</SPAN> gdb<SPAN class="punctuation token">,</SPAN> table_name <SPAN class="operator token">+</SPAN> <SPAN class="string token">"_max"</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> <SPAN class="keyword token">print</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>GetCount_management<SPAN class="punctuation token">(</SPAN>table_view<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="punctuation token">.</SPAN> arcpy<SPAN class="punctuation token">.</SPAN>Delete_management<SPAN class="punctuation token">(</SPAN>table_view<SPAN class="punctuation token">)</SPAN> <SPAN class="number token">8</SPAN> <SPAN class="number token">5</SPAN> <SPAN class="number token">5</SPAN> <SPAN class="number token">5</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
The use of a self-correlated subquery allows for selecting the maximum or minimum record for a given attribute. In the example above, a self-correlated subquery is used to select the record with the maximum value of version for each value of id.
@LanceShipman
Regarding:
"File Geodatabase does not support correlated subqueries"
Does that still apply to ArcGIS Pro 3.0.3? There seems to be a lot of stuff supported in FGDBs these days, including INNER JOIN (SQL for reporting and analysis on file geodatabases) and database views. I'd like to think correlated subqueries would be supported in this modern age.
I ask because of a related post I wrote here: File Geodatabase SQL expression to get greatest n per group
Related ideas:
BUG-000156143 - An SQL query containing the EXISTS predicate validates successfully but returns incorrect results from a file geodatabase.ENH-000156158 - Raise exception when using unsupported SQL expressions in file geodatabases.
Esri Canada Case 03264937 - Exception not raised when unsupported FGDB SQL used (correlated subquery)
10-25-2016 12:35 PMI plan on updating the documentation Post 10.5. Support of SQL Correlated Subqueries is not currently planned for the fGDB, but if a persuasive business case is submitted we will consider it.
10-25-2016 12:35 PM
I would say the "greatest 1 per group" scenario is a worthwhile business case for supporting correlated subqueries in file geodatabases. Currently, there doesn't seem to be a way to do that in FGDB SQL expressions.
It's a common requirement. For example: Selecting the most recent records based on unique values in another field
Les membres connectés peuvent publier, suivre les mises à jour, et plus encore. Nouveau ici ? Inscrivez-vous gratuitement.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.