评估空格

时间:2017-08-09 10:40:05

标签: python sql sqlite sas

我正在比较两个数据集,以查找某些列上的重复条目。

我首先使用下面的PROC SQL命令(我认为是真正的结果)在SAS中使用以下查询完成了这项工作:

proc sql;
CREATE TABLE t1 AS
SELECT a.*, b.*
FROM
    local AS a INNER JOIN neighbor AS b
    ON a.surname1 = b.surname2
    AND a.yob1 = b.yob2
    AND a.cob1 = b.cob2;
quit;

我将此结果输出到csv,提供output_sas.csv

我也使用SQLite3使用相同的查询在Python中完成了这个:

conn = sqlite3.connect(file_path + db_name)
cur = conn.cursor()
cur.execute("""
CREATE TABLE t1 AS
SELECT a.*, b.*
FROM
    local AS a INNER JOIN neighbor AS b
    ON a.surname1 = b.surname2
    AND a.yob1 = b.yob2
    AND a.cob1 = b.cob2
""")

我将此输出到csv,提供output_python.csv

问题:

输出应该相同但不是

output_sas.csv包含 123条记录而不是output_python.csv

在SAS输出文件中,有123条记录在""yob1列中包含空格yob2,例如,{{1}中的123条记录看起来像这个样本:

sas_data.csv

我发现这种差异是由yob1 yob2 cob1 cob2 surname1 surname2 "" "" 1 1 xx xx "" "" 2 2 yy yy . . . # Continues for 123 records yob1列引起的,在上面的123条记录中包含空格。 yob2文件中缺少这123条记录对。

[注意:在这项工作中,长度为零的字符串对应于缺失值]

简而言之:

SAS中的PROC SQL例程正在评估空格是否相等,即 output_python.csv

Python SQLite代码似乎正好相反,即 "" == "" -> TRUE

即使Python中有"" == "" -> FALSE,也会发生这种情况。

问题:

为什么会出现这种情况,我需要更改哪些内容才能将SQLite输出与PROC SQL输出相匹配?

注意:两个例程都使用相同的输入数据集。它们完全相同,我甚至手动修改Python代码,以确保列"" == "" -> Trueyob1包含yob2的缺失值。

更新1:

目前,我的SAS PROC SQL代码使用"",名为data1.sas7bdatlocal,名为data2.sas7bdat

要在Python中使用相同的数据集,在SAS中,我将这些数据集导出到csv并读入Python。

如果我这样做:

neighbor

Pandas将缺失值转换为import pandas as pd # read in dflocal = pd.read_csv(csv_path_local, index_col=False) dfneighbor = pd.read_csv(csv_path_neighbor, index_col=False) 。我们可以使用nan来查找每列中的nan值的数量:

isnull()

要解决空值问题,我可以通过运行显式将# find null / nan values in yob1 and yob2 in each dataset len(dflocal.loc[dflocal.yob1.isnull()]) 78 len(dfneighbor.loc[dfneighbor.yob2.isnull()]) 184 转换为长度为零nan的字符串:

""

我们可以通过测试已知的dflocal['yob1'].fillna(value="", axis=0, inplace=True) dfneighbor['yob2'].fillna(value="", axis=0, inplace=True)

来测试值是否已更新
nan

所以它们是一个长度为0的字符串。

然后通过以下方式将这些内容读入SQL:

dflocal.iloc[393].yob1
`""`
type(dflocal.iloc[393].yob1)
str

然后执行相同的SQLite3代码:

dflocal.to_sql('local', con=conn, flavor='sqlite', if_exists='replace', index=False)
dfneighbor.to_sql('neighbor', con=conn, flavor='sqlite', if_exists='replace', index=False)

即使我做了这个明确的更改 我仍然 获得相同的缺失123值,即使空值已更改为长度为零的字符串{ {1}}。

潜在解决方案

但是,如果我改为使用conn = sqlite3.connect(file_path + db_name) cur = conn.cursor() cur.execute(""" CREATE TABLE t1 AS SELECT a.*, b.* FROM local AS a INNER JOIN neighbor AS b ON a.surname1 = b.surname2 AND a.yob1 = b.yob2 AND a.cob1 = b.cob2 """) 参数导入数据集,则会为我执行从""na_filter=False的转换。

null

当我将这些数据集导入我的数据库并通过相同的SQL代码运行时:

""

HOORAY我将相同的输出作为SAS代码!

但为什么第一个解决方案不起作用?我在两种情况下都做了同样的事情(第一次使用dflocal = pd.read_csv(csv_path_local, index_col=False, na_filter=False) dfneighbor = pd.read_csv(csv_path_neighbor, index_col=False, na_filter=False") # find null / nan values in yob1 and yob2 in each dataset len(dflocal.loc[dflocal.yob1.isnull()]) 0 len(dfneighbor.loc[dfneighbor.yob2.isnull()]) 0 手动执行,第二次使用conn = sqlite3.connect(file_path + db_name) cur = conn.cursor() cur.execute(""" CREATE TABLE t1 AS SELECT a.*, b.* FROM local AS a INNER JOIN neighbor AS b ON a.surname1 = b.surname2 AND a.yob1 = b.yob2 AND a.cob1 = b.cob2 """) )。

2 个答案:

答案 0 :(得分:3)

在SAS中,字符的空值概念并不存在。它更像是一个空字符串。 但是,在大多数SQL实现中(包括SQlite,我假设),空值和空字符串将是不同的。

SAS中的空白值确实评估为"" = "" true

然而,在您的平均DBMS中,您会称之为空白值'通常是null值,而不是空字符串("")。 null=null不正确。您无法将空值与任何内容进行比较,包括空值。

可以做的是将您的SQlite更改为

CREATE TABLE t1 AS
SELECT a.*, b.*
FROM
    local AS a INNER JOIN neighbor AS b
    ON a.surname1 = b.surname2
    AND coalesce(a.yob1,'') = coalesce(b.yob2,'')
    AND a.cob1 = b.cob2

yob为空时,coalesce函数将用空字符串替换yob

请注意,如果yob1为空并且yob2实际上是空字符串,添加这些合并函数将改变null=''条件,这不是真的,到''=''这是真的。 如果这不是你想要的,你也可以这样写:

CREATE TABLE t1 AS
SELECT a.*, b.*
FROM
    local AS a INNER JOIN neighbor AS b
    ON a.surname1 = b.surname2
    AND (a.yob1 = b.yob2
        OR (a.yob1 is null AND a.yob2 is null)
        )
    AND a.cob1 = b.cob2

答案 1 :(得分:2)

听起来像是被SQLite3(和大多数DBMS)处理空值的方式所击中。在SAS中,您可以将空值与实际值进行比较,但在大多数DBMS系统中,您不能。因此,在SAS中,诸如(A = B)和(A ne B)的互补逻辑比较将总是产生一个为真,另一个为假。但是在DBMS中,当A或B或两者都为NULL时,则(A = B)和(A ne B)都将为FALSE。 NULL值既不小于也不大于另一个值。

在SAS中如果两个值都为NULL,那么它们是相等的,一个是NULL而另一个不是那么它们不相等。 NULL数值小于任何实际数字。 NULL字符变量不存在,因此只被视为空白填充值。请注意,SAS在比较字符变量时也会忽略尾随空白。

这在实践中意味着您在查询DBMS时需要添加额外的代码来处理NULL值。

ON (a.surname1 = b.surname2 or (a.surname1 is null and b.surname1 is null))
AND (a.yob1 = b.yob2 or (a.yob1 is null and b.yob2 is null))
AND (a.cob1 = b.cob2 or (a.cob1 is null and b.cob2 is null))