sql

All things SQL and JDBC...
Ramon Rios 2020-07-17T12:29:27.231300Z

Hello everyone

Ramon Rios 2020-07-17T12:29:52.231900Z

I'm trying to make that a map follow a certain order when i do query

Ramon Rios 2020-07-17T12:30:08.232300Z

For example, i have this query

{:select [:customer.customer_number :contact.name :contact.street :contact.house_number :contact.phone :contact.mobile :contact.fax :contact.email
                           [:city.name :city] :city.zip_code [:mlv.ml_value :country]]
                  :from [[:contacts :contact]]
                  :join [[:customers :customer] [:= :contact.id :customer.contact_id]
                         [:cities :city] [:= :contact.city_id :city.id]
                         [:countries :country] [:= :country.id :city.country_id]
                         [:multi_language_values :mlv] [:= :country.name_id :mlv.ml_string_id]]
                  :where [:= :mlv.language_id 1]}

Ramon Rios 2020-07-17T12:30:31.232800Z

And my maps are coming not in the order of the select:

{:cities/city aaaaa, :contacts/house_number 11, :cities/zip_code 1111, :contacts/phone 11111, :contacts/mobile 1111111, :contacts/fax , :customers/customer_number 111111, :multi_language_values/country Aaaa, :contacts/name aaaaa, :contacts/street Caaa, :contacts/email aaa.@aaa.aa}

Ramon Rios 2020-07-17T12:30:42.233100Z

I'm using next.jdbc

kwrooijen 2020-07-17T12:36:30.233800Z

Not sure why you need this to be ordered? Clojure maps don't have any order

kwrooijen 2020-07-17T12:36:44.234Z

Or at least are not sorted

kwrooijen 2020-07-17T12:37:14.234300Z

Since maps are key value pairs, I don't think you should rely on any order

kwrooijen 2020-07-17T12:40:25.234900Z

Clojure does have a sorted-map . But I don't know of next-jdbc supports that

Ramon Rios 2020-07-17T13:12:31.235400Z

Because i'm going to create a excel file with

Ramon Rios 2020-07-17T13:12:46.235800Z

So i need it into a certain order before i turn it into a excel

Johannes F. Knauf 2020-07-17T13:28:29.236300Z

@ramonp.rios What library do you use to create the excel file? How does the API look like?

Ramon Rios 2020-07-17T13:30:26.236500Z

https://github.com/matthewdowney/excel-clj

Ramon Rios 2020-07-17T13:30:31.236800Z

Using this folk

Johannes F. Knauf 2020-07-17T13:35:49.237Z

So you use it similar to the example there?

(require '[excel-clj.core :as excel])
=> nil
(def table-data
  [{"Date" "2018-01-01" "% Return" 0.05M "USD" 1500.5005M}
   {"Date" "2018-02-01" "% Return" 0.04M "USD" 1300.20M}
   {"Date" "2018-03-01" "% Return" 0.07M "USD" 2100.66666666M}])
=> #'user/table-data
(let [;; A workbook is any [key value] seq of [sheet-name, sheet-grid].
      ;; Convert the table to a grid with the table function.
      workbook {"My Generated Sheet" (excel/table table-data)}]
  (excel/quick-open workbook))

Ramon Rios 2020-07-17T13:36:40.237200Z

Yes

Johannes F. Knauf 2020-07-17T13:37:44.237400Z

That is faily interesting.

Johannes F. Knauf 2020-07-17T13:37:54.237600Z

Should not create any particular order.

Johannes F. Knauf 2020-07-17T13:38:06.237800Z

However, on that page are also examples about using it with arrays.

Ramon Rios 2020-07-17T13:39:22.238Z

I'm looking at another called Docjure.

Ramon Rios 2020-07-17T13:39:30.238200Z

Probably that one can get arrays

Johannes F. Knauf 2020-07-17T13:42:13.238400Z

Did you try it with arrays?

Ramon Rios 2020-07-17T13:58:18.238600Z

Trying

2020-07-17T14:36:15.238800Z

there's a simple idiom to get an ordered set of fields from a map:

(def field-order [:a :b :c :d :e])

#'user/field-order
(def data [{:d 2 :b 1 :c 0 :a -1}
           {:b 2 :d 1 :a 0 :c -1}])
#'user/data
user=>
(ins)user=> (map #(map % field-order) data)
((-1 1 0 2 nil) (0 2 -1 1 nil))

2020-07-17T14:36:36.239Z

when making a csv, that same "field order" vector can be used as the header row

Ramon Rios 2020-07-17T14:42:36.239200Z

I was able to use olny arrays to it

2020-07-17T14:46:38.239400Z

by "arrays" do you all mean [] - vectors? - we have arrays but they don't seem like they'd be useful here

Ramon Rios 2020-07-17T14:47:24.239600Z

yes, i got another excel lib that uses vectors at all so i was able to keep the order

seancorfield 2020-07-17T15:13:43.240500Z

@ramonp.rios The best approach for that is to have your JDBC library (`clojure.java.jdbc` or next.jdbc) return the result set as arrays.

seancorfield 2020-07-17T15:14:31.241500Z

You'll get a vector of vectors: the first vector will be the column names in the natural SQL order (what you want), and all the other vectors will be the rows, each one in column order.

Ramon Rios 2020-07-21T11:24:27.287100Z

Oh,ok

Ramon Rios 2020-07-21T11:26:28.287300Z

So, what i basicly did was to use the result set bringing arrays..

(sql/query ds
             (format-sql query)
             {:builder-fn rs/as-unqualified-arrays})
So, i was using docjure, so it understood that the first vector are the hearders and the rest of it was data

1
seancorfield 2020-07-17T15:14:55.242Z

That ought to be a convenient format for converting to CSV or Excel etc.

Ramon Rios 2020-07-17T15:34:40.242100Z

I did that.

Ramon Rios 2020-07-17T15:34:44.242300Z

Thank you

seancorfield 2020-07-17T15:41:02.242500Z

If you have found a solution to a problem you've posted on Slack, it's a courtesy to post back with the solution -- so folks don't continue to read the question and try to help further 🙂

ghadi 2020-07-17T19:41:26.244Z

What is the most efficient way to insert 500 homogenous maps into a table using next.jdbc?

seancorfield 2020-07-17T19:46:51.245200Z

Probably using next.jdbc.prepare/execute-batch!.

ghadi 2020-07-17T19:46:56.245500Z

it's not clear from the docs what the sql-params arg is to execute!

seancorfield 2020-07-17T19:47:16.246300Z

It will also depend on what DB you're using. You may need to provide additional options.

ghadi 2020-07-17T19:47:17.246400Z

it's a vector with a particular syntax, but what?

ghadi 2020-07-17T19:47:23.246600Z

sqlite database

seancorfield 2020-07-17T19:49:08.247500Z

["some SQL string" param1 param2 param3] -- one param for each ? in the SQL string

seancorfield 2020-07-17T19:49:15.247700Z

Same as clojure.java.jdbc

ghadi 2020-07-17T19:49:41.248700Z

I've forgotten 🙂

seancorfield 2020-07-17T19:49:41.248800Z

But if you use execute-batch!, you can pass batches of parameters for a single SQL string

ghadi 2020-07-17T19:49:51.249100Z

ok execute-batch! seems like what I want

seancorfield 2020-07-17T19:51:20.250300Z

You'll need to pass a vector of vals from the maps for each inserted row -- since order matters 🙂

ghadi 2020-07-17T19:51:32.250700Z

trying it out...

ghadi 2020-07-17T20:00:58.251500Z

...works. not the prettiest thing

ghadi 2020-07-17T20:01:17.251700Z

thanks @seancorfield

ghadi 2020-07-17T20:01:57.252200Z

is that preferred over next.jdbc.sql/insert-multi! ?

seancorfield 2020-07-17T20:18:36.253200Z

execute-batch! will let you send much larger groups of data than insert-multi! but for your case the latter might be faster.

seancorfield 2020-07-17T20:19:03.253800Z

But it also expects a vector of column names and then a vector of vectors for the rows of column values.

seancorfield 2020-07-17T20:19:57.255Z

c.j.j. accepted a sequence of hash maps but behind the scenes it did a separate insert for each one which caught a lot of people out (because it was very slow) even though the docs specifically called that out 🙂