Load multiple records from multiple files into mysql table - mysql

I'm trying to load different data, from different files, into multiple columns in MySQL. I'm not a big database guy, so maybe I have my data structured wrong. :)
Here's how I have it set up:
DATABASE: mydb
TABLE: aixserver1
COLUMNS: os, hostname, num_users, num_groups, pkg_epoch
shown from mysql:
+---------------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| cur_timestamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| pkg_epoch | int(11) | NO | | NULL | |
| os | char(5) | YES | | NULL | |
| hostname | char(40) | YES | | NULL | |
| num_users | int(10) | YES | | NULL | |
| num_groups | int(10) | YES | | NULL | |
+---------------+-----------+------+-----+-------------------+----------------+
So basically I want to populate pkg_epoch, os, hostname, num_users and num_groups into the database. The data I want to load is inside 5 flat files on the server. I'm using ruby to load the data.
My question is how do I load all these values from those files into my table at once. If I do my inserts one at a time, then the other records become NULL. I.E, I load data into just the hostname column, and all the other columns become NULL for that row.
What am I missing? :)

You can do this a couple ways but the trick is to use a variable placeholder. Here is an example if you used the database's LOAD DATA function:
LOAD DATA INFILE '/PATH/TO/FILE' IGNORE INTO TABLE tableName FIELDS TERMINATED BY '\t' LINES
TERMINATED BY '\r' (#skip, #skip, #skip, login_name, pwd, #skip, #skip, #skip, #skip, #skip, first_name, last_name);
You see I just set a variable #skip or #anything for the fields I don't want to include in the database and name the columns that I do want.
I can get you halfway there with this but am uncertain best approach if you build your own loader with Ruby. I would suggest you retrieve the file and let MySQL import using LOAD DATA as it'll be very performant and you can use trick above.

Related

MySQL import csv is failing with Data too long for column exception

When I'm trying to import csv into MySQL table, I'm getting an error
Data too long for column 'incident' at row 1
I'm sure the values are not higher than varchar(12). But, still I'm getting the error.
MariaDB [pagerduty]>
LOAD DATA INFILE '/var/lib/mysql/pagerduty/script_output.csv'
REPLACE INTO TABLE incidents
ignore 1 lines;
ERROR 1406 (22001): Data too long for column 'incident' at row 1
MariaDB [pagerduty]>
LOAD DATA INFILE '/var/lib/mysql/pagerduty/script_output.csv'
INTO TABLE incidents
ignore 1 lines;
ERROR 1406 (22001): Data too long for column 'incident' at row 1
While trying with REPLACE, the data is uploading only one column(which set on primary key)
MariaDB [pagerduty]>
LOAD DATA INFILE '/var/lib/mysql/pagerduty/script_output.csv'
IGNORE INTO TABLE incidents
ignore 1 lines;
Query OK, 246 rows affected, 1968 warnings (0.015 sec)
Records: 246 Deleted: 0 Skipped: 0 Warnings: 1968
**Columns:**
+----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| incident | varchar(12) | NO | PRI | NULL | |
| description | varchar(300) | YES | | NULL | |
| status | varchar(12) | YES | | NULL | |
| urgency | varchar(7) | YES | | NULL | |
| service | varchar(27) | YES | | NULL | |
| trigger | varchar(25) | YES | | NULL | |
| team | varchar(20) | YES | | NULL | |
| incident_start | datetime(6) | YES | | NULL | |
| incident_end | datetime(6) | YES | | NULL | |
| resolved_by | varchar(20) | YES | | NULL | |
+----------------+--------------+------+-----+---------+-------+
10 rows in set (0.003 sec)
By default, MySQL looks for a TAB character to separate values. Your file is using a comma, so MySQL reads the entire line and assumes it is the value for the first column only.
You need to tell MySQL that the column terminator is a comma, and while you're at it, tell it about the enclosing double quotes.
Try this:
LOAD DATA INFILE '/var/lib/mysql/pagerduty/script_output.csv' REPLACE INTO TABLE incidents
columns terminated by ','
optionally enclosed by '"'
ignore 1 lines;
Reference
If you THINK your data appears ok, and its still nagging about the too long data, how about creating a new temporary table structure and set your first column incident to a varchar( 100 ) just for grins... maybe even a few others if they too might be causing a problem.
Import the data to THAT table to see if same error or not.
If no error, then check the maximum trimmed length of the data in respective columns and analyze the data itself... bad format, longer than expected, etc.
Once resolved, then you can pull into production once you have figured it out. You could also always PRE-LOAD the data into this larger table structure, truncate it before each load so no dups via primary key on a fresh load.
I have had to do that in the past, also was efficient for pre-qualifying lookup table IDs for new incoming data. Additionally could apply data cleansing in the temp table before pulling into production.

mysql: new keyword not recognized on trigger creation

Working on mysql.5.7
Here is my bugs table
MySQL [jira_statistics]> describe bugs;
+---------------------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------------------------+--------------+------+-----+---------+-------+
| issue_key | varchar(45) | NO | PRI | NULL | |
| release_name | varchar(45) | YES | MUL | NULL | |
| issue_summary | varchar(200) | YES | | NULL | |
| story_points | int(11) | NO | | 0 | |
| qa_reopened | float | NO | | 0 | |
| done_reopened | float | NO | | 0 | |
This table is updated by periodic calls to LOAD DATA LOCAL INFILE bugs <file.csv>
Whenever this update takes place (which may either update existing lines and/or insert new ones) I want another table that has some yielded statistics to be updated via the following trigger
create trigger update_bugs_stats after insert on `jira_statistics`.`bugs` for each row
begin
delimiter ;
-- STORY POINTS -------------------------
SELECT AVG(story_points) INTO #avg_bugs_storypoints FROM `jira_statistics`.`bugs` WHERE release_name = new.release_name;
SELECT MAX(story_points) INTO #max_bugs_storypoints FROM `jira_statistics`.`bugs` WHERE release_name = new.release_name;
SELECT MIN(story_points) INTO #min_bugs_storypoints FROM `jira_statistics`.`bugs` WHERE release_name = new.release_name;
INSERT INTO storypoints_stats (release_name, avg_bugs_storypoints, max_bugs_storypoints, min_bugs_storypoints)
VALUES (relName, #avg_bugs_storypoints, #max_bugs_storypoints, #min_bugs_storypoints)
ON DUPLICATE KEY UPDATE
relName=new.release_name,
avg_bugs_storypoints=#avg_bugs_storypoints,
max_bugs_storypoints=#max_bugs_storypoints,
min_bugs_storypoints=#min_bugs_storypoints;
However this gives me the following error whenever trying to create the trigger:
Unknown column new.release_name in where clause.
Why isn't the new keyword bein recognized?
Because new is reserved as a system word
Ref: https://dev.mysql.com/doc/refman/8.0/en/keywords.html
Please modify
new.release_name ==> `new`.`release_name`
etc..
Τhe error was more stupid than I thought;
I was working directly on sql query editor and not on the triggers tab of mysql workbench so it did not parse correctly the new keyword`.

Why isn't MySQL inserting rows from CSV file? I've been using LOAD DATA INFILE wrong?

I have a CSV file containing rows just like the following one:
2,1,abc123,1,2,"Hello World"
2,1,abc123,1,2,"Hello World2"
2,1,abc123,1,2,"Hello World3"
I'm running the following query:
LOAD DATA LOCAL INFILE :path INTO TABLE errors
CHARACTER SET 'utf8'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
LINES TERMINATED BY '\n'
(import_id, type, code, row, cell, message);
It does not insert any of my rows into the database.
Here's the structure for the errors table:
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| import_id | int(10) unsigned | NO | MUL | NULL | |
| type | int(10) unsigned | NO | | NULL | |
| code | varchar(128) | YES | | NULL | |
| row | int(10) unsigned | YES | | NULL | |
| cell | varchar(32) | YES | | NULL | |
| message | varchar(128) | YES | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
I've noticed that if I change the order of the columns, it works.
For example, in my CSV file
1,abc123,1,2,"Hello World",2
1,abc123,1,2,"Hello World2",2
1,abc123,1,2,"Hello World3",2
Also changed the query:
LOAD DATA LOCAL INFILE :path INTO TABLE errors
CHARACTER SET 'utf8'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '\\'
LINES TERMINATED BY '\n'
(type, code, row, cell, message, import_id);
Why is it working with a different order for columns?
Please verify the version of your mysql and whether this option (load data infile local) is enabled by your tool that you are using, along with it being enabled on server side. It is considered a security risk and is disabled by default by newer versions of mysql server.
Here is more info on security issues about utilizing load infile local MYSQL OFFICIAL DOCS
Also pay attention that you probably need to have local_infile=1 and you can check it with the following command:
SHOW GLOBAL VARIABLES LIKE 'local_infile';
To enable it, use the following command:
SET GLOBAL local_infile = 1;
Also verify that the lines are terminated by '\n' and not by '\r\n' (this is for windows environment)
Hope that helps!

mysql table schema to actual table

I'm very new to databases, so apologies if this is an incredibly stupid quesiton. I was sent the schema of a mysql table in the body of an email. It looks like this, except it has many more rows:
+-------------------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------+------+-----+---------+-------+
| _id | varchar(40) | NO | FOO | NULL | |
| foo | text | YES | | NULL | |
| bar | text | YES | | NULL | |
| baz | text | YES | | NULL | |
| qux | datetime | YES | | NULL | |
+-------------------------+---------------+------+-----+---------+-------+
I need to create the table locally before reading in the actual data, which is in an accompanying tsv file. I'd rather not create the table schema manually, as it is a lot of columns. Is there a way to do this automatically using the schema that I was sent?
There is no way to automatically convert an ASCII-art table of that form to an SQL CREATE statement.
If you are bored and inclined to do so, I suppose you could write a utility to parse that input and generate an output.
You will either have to create the table with a query (see CREATE), or use an administrative front-end such as phpMyAdmin to enter the information in a more human-friendly manner (I believe phpMyAdmin also now has a graphical designer feature).
Some other DBMS's have table generation tools built in to their front-ends too, e.g. MS SQL Server Management Studio has a nice graphical table builder.
By the way, to pick nits, you mean to say it is a lot of columns, not rows.
Edit: Just for fun, here is a quick Linux shell script that converts most of the informational portion of your table to an SQL statement (command line parameter is input file name):
#!/bin/sh
echo "CREATE TABLE myTable ("
cat "$1" | awk '{ split($0,a,"|"); print a[2] a[3] (match(a[4],"NO")?"NOT NULL":"") " DEFAULT" a[6] ","; }' | tr -s " "
echo ");"
The following input file:
| _id | varchar(40) | NO | FOO | NULL | |
| foo | text | YES | | NULL | |
| bar | text | YES | | NULL | |
| baz | text | YES | | NULL | |
| qux | datetime | YES | | NULL | |
Generates the following output:
CREATE TABLE myTable (
_id varchar(40) NOT NULL DEFAULT NULL ,
foo text DEFAULT NULL ,
bar text DEFAULT NULL ,
baz text DEFAULT NULL ,
qux datetime DEFAULT NULL ,
);
But you still have to remove the foo line manually and replace _id with foo (and the NOT NULL DEFAULT NULL is odd, I don't actually know of MySQL will accept a null default on a not null column). It doesn't care about your KEY column. You also have to manually delete that last comma. It does do most of the work, though.
You could make a start with a good text editor by running through your schema with intelligent replace operations. But in the end it will remain a mainly manual process.

Problem querying MySQL DB

I have this project I am working on, I have a table schema, see below
+--------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------+------+-----+---------+----------------+
| codeId | int(15) | NO | PRI | NULL | auto_increment |
| code | varchar(9) | YES | | NULL | |
| status | varchar(5) | YES | | 0 | |
+--------+------------+------+-----+---------+----------------+
This table is used for authorizations of codes, however some people send codes like dsfffMUBBDG345qwewqe for authorization, please note the capitalized part. In the code column there is a code MUBBDG345. I need to be able to check from the table if any combination of 9 characters the codes sent matches any of the codes in the db.
I have tried using this query but i just does not work.
select code, codeId, status from authCodes where 'dsfffMUBBDG345qwewqe' like code;
Is this even possible with a mysql query only?
you want to use
SELECT code, codeId, status
FROM authCodes
WHERE 'dsfffMUBBDG345qwewqe' LIKE CONCAT('%', code, '%')