Saving output of a query onto a text file in Ruby - ruby

I'm trying to query a table, fetch all records, and save the result as a CSV file.
This is what I've done so far:
require 'OCI8'
conn = OCI8.new('scott','tiger','020')
file = File.open('output.csv','w') do |f|
conn.exec('select * from emp') do |e|
f.write log.join(',')
end
end
.. And while it does generate a CSV file, the problem is that all records get saved onto a single line. How can I put the data such that each record goes onto a new line ?

Well, you can use f.puts instead of f.write there, but I'd recommend you take a look at CSV module:
http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
outfile = File.open('csvout', 'wb')
CSV::Writer.generate(outfile) do |csv|
csv << ['c1', nil, '', '"', "\r\n", 'c2']
...
end
outfile.close
PS: Actually, there is another CSV library called FasterCSV, which became CSV in standard library in Ruby 1.9. But in general, any should be better than writing it yourself.

Related

Adding Headers to a created CSV file in Ruby - keep getting errors

I've been trying to use Ruby to create a CSV file from json data. I was able to create the file, but I need to add a few headers. I tried following suggestions and answers from similar questions posted here on Stack Overflow, but I keep getting errors. Can anyone give me some pointers?
Here's my code.
require 'csv'
require 'json'
CSV.open("your_csv.csv", "w") do |csv|
JSON.parse(File.open("tojson.txt").read).each do |hash|
csv << hash.values
#csv.each { |line| line['New_header'] = line[0].to_i + line[1].to_i }
end
end
And here is the error I'm getting:
Anyone have any suggestions?
This is not how you add headers to a csv file. When you generate csv content, a header row is just a regular row. And should be generated as such. Example:
CSV.open("your_csv.csv", "w") do |csv|
csv << ['new_header', 'value1', 'value2'] # the headers
JSON.parse(File.open("tojson.txt").read).each do |hash|
row = [generate, values, for, headers, above]
csv << row
end
end
You don't have a #csv variable. You have a csv one.

Ruby: Write a value to a specific location in CSV file

I'm still fairly new to coding and I'm trying to learn about manipulating CSV files.
The code below opens a specified CSV file, goes to each url in the CSV file in column B (header = url), and finds the price on the webpage.
Example data from CSV file:
Store,URL,Price
Walmart,http://www.walmart.com/ip/HP-11.6-Stream-Laptop-PC-with-Intel-Celeron-Processor-2GB-Memory-32GB-Hard-Drive-Windows-8.1-and-Microsoft-Office-365-Personal-1-yr-subscription/39073484
Walmart,http://www.walmart.com/ip/Nextbook-10.1-Intel-Quad-Core-2-In-1-Detachable-Windows-8.1-Tablet/39092206
Walmart,http://www.walmart.com/ip/Nextbook-10.1-Intel-Quad-Core-2-In-1-Detachable-Windows-8.1-Tablet/39092206
I'm having trouble writing that price to the adjacent column C (header = price) in the same CSV.
require 'nokogiri'
require 'open-uri'
require 'csv'
contents = CSV.open "mp_lookup.csv", headers: true, header_converters: :symbol
contents.each do |row|
row_url = row[:url]
goto_url = Nokogiri::HTML(open(row_url))
new_price = goto_url.css('meta[itemprop="price"]')[0]['content']
#----
#In this section, I'm looking to write the value of new_price to the 3rd column in the same CSV file
#----
end
In the past, I've been able to use:
in_file = open("mp_lookup.csv", 'w')
in_file.write(new_price)
But this doesn't seem to work in this situation.
Any help is appreciated!
The simple answer is that you can refer to the :price column in the CSV file, just like you refer to the :url column. Try this code to set the price in the CSV object in memory:
row[:price] = new_price
After you've read through all of the records, you'll want to save the CSV file again. You can save it to any filename, but we'll simply overwrite the previous file in this example:
CSV.open("mp_lookup.csv", "wb") do |csv|
contents.each do |row|
csv << row
end
end
In a real production environment, you'd want to be more fault tolerant than this, and preserve the original file until the end of the process. However, this shows how to update the values in the price column for each row, and then save the changes to a file.

How do I create a CSV file without the CSV class?

I'm using a Mac OSX version 10.8
I'm trying to create a CSV file the old fashion way, but there is a bug in my code. It should create a spreadsheet with three rows, i.e., header, and two rows of data beneath it:
File.open('table.csv', 'w') do |f|
f.puts.each {|line| puts line}
'Date','Open','High','Low','Close','Volume','Adj Close'
'10/8/2013','1676.22','1676.79','1655.03','1655.45','3569230000','1655.45'
'10/7/2013','1687.15','1687.15','1674.7','1676.12','2678490000','1676.12'
end
Can someone fix this so that it works and explain what I am doing wrong.
Thanks
File.open('table.csv', 'w') do |csv|
csv << ["Date","Open","High","Low","Close","Volume","Adj Close"]
csv << ["10/8/2013","1676.22","1676.79","1655.03","1655.45","3569230000","1655.45"]
csv << ["10/7/2013","1687.15","1687.15","1674.7","1676.12","2678490000","1676.12"]
end
This should work. You don't need an array.
Try putting your data in an array and then loop over it like this:
data = [
['Date','Open','High','Low','Close','Volume','Adj Close'],
['10/8/2013','1676.22','1676.79','1655.03','1655.45','3569230000','1655.45']
['10/7/2013','1687.15','1687.15','1674.7','1676.12','2678490000','1676.12'],
]
File.open('table.csv', 'w') do |f|
data.each{|line| f.puts line.join(',')}
end

Split output data using CSV in Ruby 1.9

I have a csv file that has 7000+ records that I process/manipulate and export to a new csv file. I have no issues doing that and everything works as expected.
I would like to change the process to where it breaks the output into multiple files. So instead of writing all 7000+ rows to the new csv file it would write the first 1000 rows to newexport1.csv and the next 1000 rows to newexport2.csv until it reaches the end of the data.
Is there an easy way to do this with CSV in Ruby 1.9?
My current write method:
CSV.open("#{PATH_TO_EXPORT_FILE}/newexport.csv", "w+", :col_sep => '|', :headers => true) do |f|
export_rows.each do |row|
f << row
The short answer is "no". You'll want to adjust your current code to split up the set and then dump each subset to a different file. This ought to be pretty close:
export_rows.each_slice(1000).with_index do |rows, idx|
CSV.open("#{PATH_TO_EXPORT_FILE}/newexport-#{idx.to_s}.csv", "w+", :col_sep => '|', :headers => true) do |f|
rows.each { |row| f << row }
end
end
Yes, there is.
It's embedded in Ruby 1.9
Check this link
To read:
CSV.foreach("path/to/file.csv") do |row|
# manipulate the content
end
To write:
CSV.open("path/to/file.csv", "wb") do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# something else
end
I think that you'll need to combine one inside the other.
FasterCSV is the standard CSV library since ruby 1.9, you can find a lot of example code in the examples folder:
https://github.com/JEG2/faster_csv/tree/master/examples
For the example code to work, you should change:
require "faster_csv"
for
require "csv"

How to create CSV file using CSV gem in ruby 1.9.2?

I am new to ruby 1.9.2. How to generate CSV file in a single ruby script file?
Here, I wrote a ruby script,
require 'rubygems'
require 'pg'
require 'active_record'
require 'csv'
class AttachEmail
def generate_csv
begin
filename = "csvout.csv"
users = User.all
users.each do |u|
products = Product.find(:all,:conditions=>["user_id=?",u.id])
CSV.open(filename, 'w') do |csv|
# header row
user_name = u.name
csv << ['Report']
csv << ['Name','Product', 'Item Count']
products.each do |product|
csv << [user_name, product.title,product.count]
end
end
end
rescue Exception => e
puts e
end
end
generate= AttachEmail.new
generate.generate_csv
When i run this script.it will produce output like below,
A B C
0 Report
1 Name,Product,Item Count
2 user1,PD123,10,990
But I need output like, separate column, Please can you kind me ? Thanks in advance
First of all, you need to swap loops if you are trying to put all the user data in the same file, and not overwrite it for every user:
CSV.open(filename, 'w') do |csv|
users.each do |u|
products = Product.find(:all,:conditions=>["user_id=?",u.id])
Next, fix your Excel (I suspect the output is taken from it, right?) to use comma as a separator, not a "space or comma".
Come back with the file contents attached and an example of CSV file which works for you if it still doesn't work.

Resources