MySQL datetime列WHERE col IS NULL失败

时间:2018-01-10 00:50:54

标签: python mysql sqlalchemy scrapy

我无法让我的基本SQL查询工作,因为它返回0值,尽管有明显的空值

查询

SELECT
  *
FROM
  leads AS l
  JOIN closes c ON l.id = c.lead_id
 WHERE
  c.close_date IS NULL

DDL

CREATE TABLE closes
(
  id               INT AUTO_INCREMENT
    PRIMARY KEY,
  lead_id          INT          NOT NULL,
  close_date       DATETIME     NULL,
  close_type       VARCHAR(255) NULL,
  primary_agent    VARCHAR(255) NULL,
  price            FLOAT        NULL,
  gross_commission FLOAT        NULL,
  company_dollar   FLOAT        NULL,
  address          VARCHAR(255) NULL,
  city             VARCHAR(255) NULL,
  state            VARCHAR(10)  NULL,
  zip              VARCHAR(10)  NULL,
  CONSTRAINT closes_ibfk_1
  FOREIGN KEY (lead_id) REFERENCES leads (id)
)
  ENGINE = InnoDB;

CREATE INDEX lead_id
  ON closes (lead_id); 

我应该提一下,我使用python web scraper和SQLAlchemy插入数据。如果数据未被删除,则插入时将为None

这是datagrip的屏幕截图,显示行

中的空值

enter image description here

修改

好吧所以我继续在表格中的某些条目上运行以下内容,其值已经是<null>

UPDATE closes
  SET close_date = NULL
WHERE
  lead_id = <INTEGERVAL>
; 

现在有趣的是,在运行原始查询时,我确实返回了我运行更新查询的2条记录(预期结果)。这将使我相信问题在于我的SQLAlchemy模型如何映射插入值。

models.py

class Close(db.Model, ItemMixin):
    __tablename__ = 'closes'

    id = db.Column(db.Integer, primary_key=True)
    lead_id = db.Column(db.Integer, db.ForeignKey('leads.id'), nullable=False)
    close_date = db.Column(db.DateTime)
    close_type = db.Column(db.String(255))
    primary_agent = db.Column(db.String(255))
    price = db.Column(db.Float)
    gross_commission = db.Column(db.Float)
    company_dollar = db.Column(db.Float)
    address = db.Column(db.String(255))
    city = db.Column(db.String(255))
    state = db.Column(db.String(10))
    zip = db.Column(db.String(10))

    def __init__(self, item):
        self.build_from_item(item)

    def build_from_item(self, item):
        for k, v in item.items():
            setattr(self, k, v) 

但我相信,如果没有从网站上删除任何值,则值为py None。我的理解是SQLAlchemy会在插入时将None映射到NULL,并且假设nullable=True是默认设置,可以在生成的DDL上看到,我仍然感到茫然为什么它似乎是NULL,而实际上它并不是那样的行为。

编辑2

只有在我认为问题发生的地方,我的蜘蛛实际上会抓取数据并将其分配给Item,如下所示

closes.py

# item['close_date'] = None at this point
try:
    item['close_date'] = arrow.get(item['close_date'], 'MMM D, YYYY').format('YYYY-MM-DD')
except ParserError as e:
    # Maybe item['close_date'] = None here?
    spider.logger.error(f'Parse error: {item["close_date"]} - {e}')

在我写的python代码中,这似乎是问题出现的地方。但如果arrow.get引发异常,item['close_date']的值仍应为None。如果不是这种情况,即使它不能解释为什么看起来记录值为NULL,甚至认为它的行为不像它。

1 个答案:

答案 0 :(得分:1)

我猜你是否遇到了连接问题,而不是NULL值。以下查询为我返回1个结果。有关您的数据,用于查询的软件(我使用SQL Yog测试过)以及适用版本的更多信息可能有所帮助。

修改

可能是您遇到了MySQL的“零日期”问题。 https://dev.mysql.com/doc/refman/5.7/en/date-and-time-types.html

  

MySQL允许您存储&#39; 0000-00-00&#39;作为一个“假人   date。“在某些情况下,这比使用NULL值更方便   并使用较少的数据和索引空间。要禁用&#39; 0000-00-00&#39;,请启用   NO_ZERO_DATE模式。

我已更新下面的SQL数据,以在INSERT和SELECT的WHERE中包含零日期。

DROP TABLE IF EXISTS closes;
DROP TABLE IF EXISTS leads;

CREATE TABLE leads (
  id INT(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

INSERT  INTO leads(id) VALUES (1),(2),(3);

CREATE TABLE closes (
  id INT(11) NOT NULL AUTO_INCREMENT,
  lead_id INT(11) NOT NULL,
  close_date DATETIME DEFAULT NULL,
  close_type VARCHAR(255) DEFAULT NULL,
  primary_agent VARCHAR(255) DEFAULT NULL,
  price FLOAT DEFAULT NULL,
  gross_commission FLOAT DEFAULT NULL,
  company_dollar FLOAT DEFAULT NULL,
  address VARCHAR(255) DEFAULT NULL,
  city VARCHAR(255) DEFAULT NULL,
  state VARCHAR(10) DEFAULT NULL,
  zip VARCHAR(10) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY lead_id (lead_id),
  CONSTRAINT closes_ibfk_1 FOREIGN KEY (lead_id) REFERENCES leads (id)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

INSERT  INTO closes(id,lead_id,close_date,close_type,primary_agent,price,gross_commission,company_dollar,address,city,state,zip) 
VALUES 
(1,3,'0000-00-0000',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(2,1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(3,2,'2018-01-09 17:01:44',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);

SELECT
  *
FROM
  leads AS l
  JOIN closes c ON l.id = c.lead_id
 WHERE
  c.close_date IS NULL OR c.close_date = '0000-00-00';