如何从Clojure中的文本文件动态编写MySQL查询

如何从Clojure中的文本文件动态编写MySQL查询,mysql,clojure,Mysql,Clojure,如何从一列ID的输入文本文件中读取并生成以下格式的MySQL查询: SELECT col1,col2,col3 FROM Orders WHERE Id IN ('inputId1','inputId3','inputId3'); 输入文件中的ID以/n分隔,应转换为MySQL查询中用引号括起来的逗号分隔的ID列表 (ns export.core (:require [clojure.java.jdbc :as j]) (:gen-class)) (defn -main [&

如何从一列ID的输入文本文件中读取并生成以下格式的MySQL查询:

SELECT col1,col2,col3 FROM Orders WHERE Id IN ('inputId1','inputId3','inputId3');
输入文件中的ID以/n分隔,应转换为MySQL查询中用引号括起来的逗号分隔的ID列表

(ns export.core
  (:require [clojure.java.jdbc :as j])

  (:gen-class))

(defn -main [& args]

  ;; Get home directory
  (def out-file
    (str (System/getProperty "user.home") "/Desktop/export.txt"))

  (def in-file
    (str (System/getProperty "user.home") "/Desktop/orders.txt"))

  ;; Get string of order-ids
  (def order-ids-string (slurp in-file))

  ???????????
  ???????????

  ;; Connect to database
  (def db {:subprotocol "mysql"
           :subname "XXXXXXXX"
           :user "XXXXXXX"
           :password "XXXXXXX"})

  ;; Get headers
  (def header-seq
    (j/query db ["DESCRIBE Orders"] :row-fn :field))

  (def header-str
    (str (clojure.string/join "\t" header-seq) "\n"))

  ;; Get product results and spit data to file
  (def header-keys
    (into []
       (map keyword
          (map clojure.string/lower-case header-seq))))

  (def data-seq
    (j/query db [<needed sql query>]))

  (defn select-values [map]
    (reduce #(conj %1 (map %2)) [] header-keys))

  (spit out-file header-str)

  (doseq [row data-seq]
    (spit out-file
      (str (clojure.string/join "\t" (select-values row)) "\n")
     :append true)))

如果我正确理解了您的问题,我将使用seq行、string/join和format来形成查询:

首先是一些测试数据:

(spit "/tmp/input-file" "id1\nid2\nid3\nid4\n")
然后让我们读回它并形成一个字符串

user> (let [ids (line-seq (clojure.java.io/reader "/tmp/input-file"))
            col-names (clojure.string/join "," (map #(str "col" %) (range 1 (inc (count ids)))))
            col-ids (clojure.string/join "," (map #(str "'"% "'") ids))]
        (format "SELECT %s FROM Orders WHERE Id IN (%s);" col-names col-ids))

"SELECT col1,col2,col3,col4 FROM Orders WHERE Id IN ('id1','id2','id3','id4');"
我猜order id的数量与文件中的行数匹配,并且它们的名称中应该包含序号

正如amalloy指出的,使用查询参数基本上总是更好的:

user> (let [ids (line-seq (clojure.java.io/reader "/tmp/input-file"))
            col-names (clojure.string/join "," (map #(str "col" %) (range 1 (inc (count ids)))))            
            question-marks (clojure.string/join "," (repeat (count ids) "?"))]
        (list 'exec-raw (format "SELECT %s FROM Orders WHERE Id IN (%s);" col-names question-marks) ids))
(exec-raw "SELECT col1,col2,col3,col4 FROM Orders WHERE Id IN (?,?,?,?);" ("id1" "id2" "id3" "id4"))

将list exec raw替换为用于进行SQL调用的任何函数

不幸的是,id1恰好是';删除表格命令;-。在?、?中输出Id更安全?然后将实际的ID列表作为参数传递给查询。如果您是从文件中获取列名,那么就没什么可做的了:-/假设这个问题是关于形成字符串的-在答案中添加了这一点,因为最终所有内容都会被剪切并粘贴到somones代码中。我认为假设列名正在生成,并且也与ID相对应是很奇怪的。我只使用col1..col3作为固定列名;这就成为了一个非常常见问题的正确答案。谢谢你的回答。让我澄清几件事。列名将只是我想要拉的任何列。col1、col2等只是示例的占位符,永远不会更改。ID是来自不同电子商务市场的订单ID,因此它们的长度不同,不会增加,而是随机的