spark-mysql:SQLException: Subquery returns more than 1 row

SQLException: Subquery returns more than 1 row

在工作中遇到一個寫入數據庫的問題
寫入數據庫的dataFrame結構數據如下
dataFrame1:

sumDatemm c1 c2 c3 c4 c5
201903281535 494708 255872 253937 11924 24844

dataFrame2:

sumDatemm c1 c2 c3 c4 c5
201903280755 477217 218232 216556 9630 17430

mysql的建表語句

CREATE TABLE `TABLE_1` (
  `sumDatemm` text NOT NULL,
  `c1` bigint(20) NOT NULL,
  `c2` bigint(20) NOT NULL,
  `c3` bigint(20) NOT NULL,
  `c4` bigint(20) DEFAULT NULL,
  `c5` bigint(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

出現的錯誤

在寫第一條記錄的時候沒有出現問題
但是第二條記錄報瞭如下錯誤

19/03/28 15:21:59 WARN scheduler.TaskSetManager: Lost task 3.0 in stage 322.0 (TID 8791, th04-ywy-hpdl380-057, executor 5): java.sql.BatchUpdateException: Subquery returns more than 1 row
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024)
        at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$.savePartition(JdbcUtils.scala:218)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$saveTable$1.apply(JdbcUtils.scala:280)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$saveTable$1.apply(JdbcUtils.scala:279)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$33.apply(RDD.scala:920)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$33.apply(RDD.scala:920)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:1888)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:1888)
        at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:66)
        at org.apache.spark.scheduler.Task.run(Task.scala:89)
        at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:242)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.sql.SQLException: Subquery returns more than 1 row
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976)
        ... 14 more

19/03/28 15:21:59 ERROR scheduler.TaskSetManager: Task 3 in stage 322.0 failed 4 times; aborting job
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024)
        at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$.savePartition(JdbcUtils.scala:218)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$saveTable$1.apply(JdbcUtils.scala:280)
        at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$saveTable$1.apply(JdbcUtils.scala:279)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$33.apply(RDD.scala:920)
        at org.apache.spark.rdd.RDD$$anonfun$foreachPartition$1$$anonfun$apply$33.apply(RDD.scala:920)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:1888)
        at org.apache.spark.SparkContext$$anonfun$runJob$5.apply(SparkContext.scala:1888)
        at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:66)
        at org.apache.spark.scheduler.Task.run(Task.scala:89)
        at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:242)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.sql.SQLException: Subquery returns more than 1 row
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
        at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
        at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
        at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
        at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976)
        ... 14 more

分析問題

從字面看來是返回的子查詢結果多餘一行,但是我本身插入的記錄就只有一行,怎麼會有多餘一行的錯誤呢?
於是把dataFrame的內容輸出,結果也確實只有一條記錄。
況且我插入數據並沒有查詢的操作和過濾的條件,哪來的子查詢呢?
根據錯誤去度娘上搜一下,基本上答案都是一樣的,都是類似下面的語句

select * from table1 where table1.colums=(select columns from table2);
(select columns from table2) 這一段的值有多個

解決辦法如下
1)如果是寫入重複,去掉重複數據。然後寫入的時候,可以加邏輯判斷(php)或者外鍵(mysql),防止數據重複寫入。
(我實際開發中遇到的就是數據重複寫入的情況,在數據庫查到有相同的數據兩條,這不符原本的原本的業務需求)
2)在子查詢條件語句加limit 1,找到一個符合條件的就可以了
select * from table1 where table1.colums=(select columns from table2 limit 1);
3)在子查詢前加any關鍵字
select * from table1 where table1.colums=any(select columns from table2);
[來源:關於mysql錯誤:Subquery returns more than 1 row]


但是我在dataFrame寫mysql的時候並沒有類似的語句,貌似不是這個問題。
百度、google了差不多一個小時都沒區解決,只能求救隊友了。

高手分析問題

跟同事說明相關情況
嘗試手動插入數據
發現手動插入第二條記錄也失敗了
再嘗試拆如第一條記錄,居然也失敗了,可是在建表的時候可沒有創建唯一鍵的
根據報錯猜測可能是某個字段重複導致失敗,於是修改第一條記錄某些字段的值,嘗試插入數據。
最後發現,c1這個列的值只要在數據庫中有一樣的數據就會失敗。
這個列有問題。

定位問題
後面去看了表格的詳細信息
發現這張表還有一個觸發器,當這張表有插入新紀錄的時候,會觸發一個插入其他標的操作,其中涉及到了c1字段
在看了觸發器的信息後,發現了問題

create trigger badQuaUpdate 
after insert on TABLE_1 
for each row        
begin  
declare c int;
set c = (select C1-C2 from TABLE_1 where c1=new.c1);
insert into TABLE_2(C1,C2) values (NEW.sumDatemm,c);
end

在這個出發其中where c1=new.c1出現了數據重複
所以根據一開始百度的解決辦法修改

create trigger badQuaUpdate 
after insert on TABLE_1 
for each row        
begin  
declare c int;
set c = (select C1-C2 from TABLE_1 where sumDatemm=new.sumDatemm);
insert into TABLE_2(C1,C2) values (NEW.sumDatemm,c);
end

sumDatemm=new.sumDatemm中sumDatemm的值是唯一的
修改觸發器後,第一條記錄順利插入了
感慨:度娘也不一定不靠譜,只是有時沒有找到真正錯誤的位置
參考文檔:
關於mysql錯誤:Subquery returns more than 1 row

本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章