Skip to content

Batch import multiple CSV files at once - #1018

Merged
MKleusberg merged 7 commits into
sqlitebrowser:masterfrom
iKlsR:cvs-multi-import
Jun 16, 2017
Merged

MKleusberg merged 7 commits into
sqlitebrowser:masterfrom
iKlsR:cvs-multi-import

Conversation

@iKlsR

@iKlsR iKlsR commented May 23, 2017 •

Copy link
Copy Markdown
Member

Allow for batch importing multiple CSV files at once using the import CSV dialog

  • You can choose to import to separate tables using the filename
  • Interactively pick which files you want to import
  • Match similar files that share the same columns to import into one table

Fixes #1002

Code could be a lot slimmer, didn't poke around as much as I could, "first timer" so a bit of reuse and ideally we should be able to fetch headers without running through the entire file (so the last commit was more of a poc) but would make for a more streamlined experience. Suggestions and improvements welcome ofc.

iKlsR added 4 commits May 21, 2017 11:53
- Tweak input checker
- Preserve old file import as not to cause any unforeseen breaks
- Allow ignoring file name when importing multiple files to tables
- Mass toggle several files for import
@justinclift

Copy link
Copy Markdown
Member

Oh wow. Animated gif showing the new behaviour in the PR.

Now that's got to be a gold standard for PR things-to-do. 😁

@justinclift
justinclift requested a review from MKleusberg May 24, 2017 00:47
@karim

karim commented May 25, 2017

Copy link
Copy Markdown
Member

Impressive! 😄

Few questions:

  • How did you add the files? (Did you associate .csv files with DB4S? If so, is there any limit, by the OS, on how many files to open like this?)
  • What if the user add a file using File > Import > CSV? (Can he add more once this dialog is open?)

Not questioning your work, it looks very nice. But we need to document this behavior.

Thanks for your hard work 👍

@justinclift

justinclift commented May 25, 2017 •

Copy link
Copy Markdown
Member

@karim This PR updates File → Import → CSV to allow selecting multiple files. 😉

@karim

karim commented May 25, 2017

Copy link
Copy Markdown
Member

Ahhh. Good to know. Thanks @justinclift 😄

@chrisjlocke

Copy link
Copy Markdown
Member

If so, is there any limit, by the OS, on how many files to open like this?

Depends on the OS and version. Some older versions of Windows have a hard coded limit of 200 files.

@iKlsR

iKlsR commented May 25, 2017 •

Copy link
Copy Markdown
Member Author

@karim

How did you add the files? (Did you associate .csv files with DB4S? If so, is there any limit, by the OS, on how many files to open like this?)

The way this feature worked initially and still does with this multiple selection variation is that it fetches the list of names first (that a user can then cherry pick from) then opens a stream, parses and performs actions after in a sequential order over the selected files. The open dialog filters what formats are allowed and the internal parser will warn/skip/err on bad files (invalid csvs). I had a folder with ~7k files with thousands of rows and including decoding and inserting took a little over half hour on a Dell XPS 15 running x64 Win 10.

What if the user add a file using File > Import > CSV? (Can he add more once this dialog is open?)

I added an (experimental until review) feature to Match similar files by checking headers (the green highlight in the gif above) so once you have selected a list of files there is no need to manually sort them before to ensure they are in the same format, hence no need to prompt for more files.

@chrisjlocke Anything below WinXP was hardcoded due to memory constraints and dependent on runtimes. IIRC WinXP itself had a limit of 1024 * 2 and I'd like to think modern OSes limits are more denoted by available memory (don't quote me on that ;).

@MKleusberg MKleusberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this, @iKlsR 👍 I'll need some time to review this but my first impression is very good. I hope I'll finish the review over the weekend 😄

@MKleusberg MKleusberg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor thing I've noticed so far: in the Import CSV dialog you could update the tab order because right now the newly added items come after the preview table view and the Separate tables checkbox comes after the file list.

@iKlsR

iKlsR commented May 26, 2017

Copy link
Copy Markdown
Member Author

@MKleusberg Ah! Thanks, forgot about that and looking forward to it.

Comment thread src/ImportCsvDialog.cpp Outdated
}
}

sqlb::FieldVector ImportCsvDialog::fetchCsvHeader(const QString& fileName)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is more or less a copy of importCsv(). I think we should modify it slightly, so it can be called from inside importCsv() as well to share the common code. Maybe change it to take a pointer to a CSVParser object and use that instead of taking a file name and opening the file etc. Though I'm not exactly sure how to do that ideally...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I'm not exactly sure how to do that ideally...

Had the same thought then that :), it was a bit tricky seeing how the FieldVecs and csv object are used because I didn't want to upset or refactor too much code initially but I'll come up with something.

Comment thread src/ImportCsvDialog.cpp Outdated

QTextStream tstream(&file);
tstream.setCodec(currentEncoding().toUtf8());
csv.parse(tstream);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When fetching just the headers, you should be able to pass 1 as the second argument to parse(), like this:

csv.parse(tstream, 1);

This limits the number of records to just the first one which should be enough for the header. This way you don't have to parse the entire file and (if this code isn't shared with importCsv()) you can get rid of the progress dialog entirely to simplify the code a bit and prevent any flickering from quickly opening and closing windows.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the holy grail, I knew I forgot something and hoped there would be a way to just get the header (didn't look hard enough really). Thanks for the clarification.

@MKleusberg

Copy link
Copy Markdown
Member

Hi Ricardo! Sorry for the delay! I've finally got around to review your entire PR 😄 It looks very, very well done. Besides the tab order thing I have only added two more comments but these are somehow related. They are both about the fetchCsvHeader() function that you have already mentioned yourself. Right now I'm not entirely sure how to solve that best but I'm fine with any way of sharing the code in fetchCsvHeader() and importCsv().

One extra thought I had is that it would be nice to specify table names in 'Separate tables' mode. Right now a new table is created for each file but ideally you would be able to set a table name for each file and default it to the file name. This could be done by making the table name field editable and let it show the table name for the currently selected table, or by adding an extra column to the file list view. But that's just an idea. Your PR is definitely already a huge improvement the way it is 😄 If you ever feel like implementing this idea it can always be done in a second PR.

@iKlsR

iKlsR commented Jun 2, 2017

Copy link
Copy Markdown
Member Author

Thanks! 😊 Perfect timing as well, can add it to my free time session tomorrow.

@MKleusberg

Copy link
Copy Markdown
Member

Awesome 😄 Looking forward to the update.

@iKlsR

iKlsR commented Jun 13, 2017 •

Copy link
Copy Markdown
Member Author

Changes will be up in a few™, was a bit busy.

@iKlsR

iKlsR commented Jun 15, 2017 •

Copy link
Copy Markdown
Member Author

@MKleusberg Done, think I found the cleanest way to delegate and reuse the csv and field generation, fixed tab order and incorporated your suggestion to make each table have a unique name. Also added a auto toggle to not show progress dialog when matching similar files. Overall, the dialog feels a lot smoother and snappy.

@MKleusberg

Copy link
Copy Markdown
Member

Awesome! 👍 This is looking really good now. I think we can mention this feature (maybe including you gif) in the Highlights section of the next release notes. I'll keep it in 7 commits instead of squashing them into one, too, because they are nice, separate units. Thanks again for your efforts here 😉

Oh, and even though it's a little late already: welcome to the team, @iKlsR! 😄

@MKleusberg
MKleusberg merged commit 357faee into sqlitebrowser:master Jun 16, 2017
@iKlsR
iKlsR deleted the cvs-multi-import branch March 7, 2019 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants