SQL学习

【参考文献】

本·福达:《SQL必知必会》,第5版,刘晓霞、 钟鸣译,北京:人民邮电出版社,2020年

基本概念

DBMS:database management system(数据库管理系统)

提取信息

SELECT

多条 SQL 语句必须以分号( )分隔。
SQL 语句不区分大小写,因此 SELECT select 是相同的
SQL 语句可以写成长长的一行,也可以分写在多行。
SELECT * FROM Products; 星号(*)通配符可以做到检索所有的列。

SQL应用案例:提取北宋政区

在CHGIS的数据中,需要提取北宋(960-1127)时期的政区。画分析草图,可以知道,如果按照Begin Year 和 End Year ( 用a b c d e f表示)作为筛选标准,一共有6种可能的情况,其中4种情况的年代符合北宋的时间区间。

b1<960  and   960 <b2 < 1127

c1<960 and 1127<c2

960<d1<1127 and 960<d2<1127

960<e1<1127 and  1127<e2

不符合的是:

a1<a2<960 (北宋前的政区)

1127<f1<f2    (北宋后的政区)

根据以上的分析,写如下SQL语句。

SELECT * FROM v6_time_pref_utf_wgs84 WHERE:
("BEG_YR" <=960) AND (960 <= "END_YR" <=1127)

但是,该句语法错误。原因在于,(960 <= "END_YR" <=1127) 这个得分开写,用AND连接,否则机器识别不了。更正后如下:

("BEG_YR" <=960) AND (960 <= "END_YR" AND "END_YR" <=1127);
("BEG_YR" <=960) AND (1127 <= "END_YR" );
 (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND (960 <= "END_YR" AND "END_YR" <=1127 );
 (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND ( "END_YR" >= 1127 );

于是,运行这个语句。

在Arcgis图层的查询构建器中运行,成功验证了表达式。运行后效果如下:

不过,这个政区显然不全。所以,需要回顾,考虑一下问题出在哪里。

可能的原因是CHGIS的数据本来就不全,有遗漏。

逻辑结构

AND 和OR

如下代码所示:

((("BEG_YR" <=960) AND (960 <= "END_YR" AND "END_YR" <=1127)) OR (("BEG_YR" <=960) AND (1127 <= "END_YR" )) OR 
( (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND (960 <= "END_YR" AND "END_YR" <=1127 )) OR 
( (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND ( "END_YR" >= 1127 ))) AND "NAME_CH" LIKE '%军'

用多重括号,将筛选条件并列在一起。

然后,可以加上AND语句,构建新的筛选条件。

如图所示,这是带以“军”为名称的宋代行政区。

用同样的这段代码,获得所有的宋代“军”级行政位置点。

((("BEG_YR" <=960) AND (960 <= "END_YR" AND "END_YR" <=1127)) OR (("BEG_YR" <=960) AND (1127 <= "END_YR" )) OR 
( (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND (960 <= "END_YR" AND "END_YR" <=1127 )) OR 
( (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND ( "END_YR" >= 1127 ))) AND "NAME_CH" LIKE '%军'

效果如下图所示

但是,下面遇到的问题是,存在同名现象,或者某些字条信息,虽然时间不同,但是名字相同。需要将同名的只保留一个。如何操作?

SQL应用:提取唐代政区

如下代码:

((("BEG_YR" <=618) AND (960 <= "END_YR" AND "END_YR" <=907)) OR (("BEG_YR" <=618) AND (907 <= "END_YR" )) OR 
( (618 <= "BEG_YR" AND "BEG_YR" <=907) AND (618 <= "END_YR" AND "END_YR" <=907 )) OR 
( (618 <= "BEG_YR" AND "BEG_YR" <=907) AND ( "END_YR" >= 907 ))) AND "NAME_CH" LIKE '%州'

SQL应用:提取西汉政区

((("BEG_YR" <=-202) AND (-202 <= "END_YR" AND "END_YR" <=8)) OR (("BEG_YR" <=-202) AND (8 <= "END_YR" )) OR 
( (-202 <= "BEG_YR" AND "BEG_YR" <=8) AND (-202 <= "END_YR" AND "END_YR" <=8 )) OR 
( (-202 <= "BEG_YR" AND "BEG_YR" <=8) AND ( "END_YR" >= 8 ))) AND "NAME_CH" LIKE '%县'

属性表去重

问题:

Arcgis软件的一个屬性表名称为“唐朝县”,属性表中有多个字段,其中一个字段为"NAME_CH",该字段下面有一些同名的数据,这些同名的数据,只需要保留一个,请问如何操作?如何写SQL语言?

DISTINCT

DISTINCT 关键字,顾名思义,它指示数据库只返回不同 的值

下面想将SQL语句进一步优化:

SELECT DISTINCT "NAME_CH"  FROM v6_time_pref_utf_wgs84 WHERE:
("BEG_YR" <=960) AND (960 <= "END_YR" AND "END_YR" <=1127);
("BEG_YR" <=960) AND (1127 <= "END_YR" );
 (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND (960 <= "END_YR" AND "END_YR" <=1127 );
 (960 <= "BEG_YR" AND "BEG_YR" <=1127) AND ( "END_YR" >= 1127 );

但是,遗憾的是该表达式是有错误的。

错误的原因,可能是Arcgis查询构建器的界面中,已经有了该语句:

SELECT * FROM v6_time_pref_utf_wgs84 WHERE:

所以,就不能再使用另外的SELECT语句。

SELECT DISTINCT "NAME_CH"  FROM v6_time_pref_utf_wgs84 WHERE:

查询构建器

针对这个情况,只需要在“图层属性”界面中,输入SQL语言,点击“确定”后,出现“查询构建器”,这个时候,SQL第一句就变为输入的句子了。

但是,在操作的时候,发现语句是有问题的,无法执行。

现在,将问题明确一下:

Arcgis屬性表中,有多个字段,其中一个字段为"NAME_CH",该字段下面有一些同名的数据,这些同名的数据,只需要保留一个,请问如何操作?如何写SQL语言?

实际上,最简单的是这样子的:

选中该字段,然后点击“获取唯一值”。

然后输入常规的SQL语言,这个时候再点击“确定”,这个时候,就能把众多在“NAME_CH”字段同名数据,只保留一个。

但是这个又失败了。

SELECT DISTINCT 'NAME_CH'  FROM 唐朝县 WHERE:
 "NAME_CH" LIKE '县'

Python安装包 arcpy

Arcgis软件的一个屬性表名称为“唐朝县”,属性表中有多个字段,其中一个字段为"NAME_CH",该字段下面有一些同名的数据,这些同名的数据,只需要保留一个,请问如何操作?如何在Arcgis中写python语言?

于是,可以尝试用Python的办法。

import arcpy  
  
# 设置你的工作空间(即,你的数据所在的位置)  
arcpy.env.workspace = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
  
# 输入和输出表  
input_table = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
output_table = "唐朝县_cleaned.shp"  
  
# 定义一个函数来检查重复的行并删除  
def remove_duplicates(input_table, output_table):  
    # 创建一个查询,选择NAME_CH字段的所有唯一值  
    query = "NAME_CH IN (SELECT DISTINCT NAME_CH FROM 唐朝县)"  
      
    # 使用查询创建新的输出表  
    arcpy.CopyRows_management(input_table, output_table, where_clause=query)  
      
# 调用函数进行清理  
remove_duplicates(input_table, output_table)

以上是人工智能生成的代码。

精简后如下:

import arcpy    
arcpy.env.workspace = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
input_table = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
output_table = "唐朝县_cleaned.shp"  
def remove_duplicates(input_table, output_table):  
    query = "NAME_CH IN (SELECT DISTINCT NAME_CH FROM 唐朝县)"  
    arcpy.CopyRows_management(input_table, output_table, where_clause=query)  
remove_duplicates(input_table, output_table)

但是,运行后,并没有成功。

运行之后,出现效果如上。于是又询问文心一言,修正后的代码如下:

import arcpy    
arcpy.env.workspace = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
input_table = "E:\DH\Map\【历史】政区\唐朝时期 政区\唐朝县.shp"  
output_table = "唐朝县_cleaned.shp"  
def remove_duplicates(input_table, output_table):  
    query = "NAME_CH IN (SELECT DISTINCT NAME_CH FROM 唐朝县)"  
    arcpy.CopyRows_management(input_table, output_table,query)  
remove_duplicates(input_table, output_table)

然后,得到了新的表格。但是,里面的数据并没有变化。

那么如何进一步优化呢?显然,需要想一些更好的方法。


 

【心得】