rails how to create record with id - mysql

I'm using rails v3.0.9 and Mysql database.
I'm migrating the tables with existing data.
I've users table and all other tables contains the user_id column and now i need seperate the users into two (users & customers) tables,
So i need to migrate the new customers table with existing users records where the user type with customer
I need to create a customers table and set the id of users records with user type as customer,
which will be easy instead of migrating many of other tables(which is used only by customers) by checking every record with user's user type and assign the new id of customers table.
Tables looks like
users table:
id | name | ...
------------------------------
1 | aaa | ...
2 | bbb | ...
4 | ddd | ...
6 | fff | ...
customers table
id | name | ...
-------------------------------
3 | ccc | ...
5 | eee | ...
7 | ggg | ...
When i'm migrating users existing data
In my migration file
def up
create_table(:customers) do |t|
t.string :name
end
User.joins(:user_type).where(:user_type => {:type_name => 'customer'}).find_in_batches(:batch_size => 100){ |users|
users.each {|user|
customer = Customer.new
customer.id = user.id
customer.name = user.name
customer.save(:validate => false)
}
}
end
Also tried
Customer.create!(:id => user.id) instead of save method
Is this correct?
Is there any way to assign the primary id ?
If i'm going wrong give me some suggestion to do it in right way...

Mysql allow to insert the record with value of primary id column.
In Rails, you can execute any sql query by supplying to execute method
For example:
sql = "insert into users(id, username) values(10, 'iam')"
ActiveRecord::Base.connection.execute(sql)

Related

mysql On Duplicate value in field, insert new row with new value

I want to add a new record in a table if duplicate value enters in a unique field. I don't want to update the existing one but want to add a new record by modifying the unique field value.
Is this possible in mysql?
EDIT:
Edited after user comment on this post:
You need write table locking on both of those two processes.
A WRITE lock has the following features:
The only session that holds the lock of a table can read and write data from the table.
Other sessions cannot read data from and write data to the table until the WRITE lock is released.
Also look at SQL UNIQUE Constraint
BEFORE EDIT:
Yes it is possible. And it took me awhile to figure it out. I build this on your input and compering values as test1, test2 etc, where test is always the same and has trailing number. As you specified.
It can be done as MySQL TRANSACTION in 4 steps.
Lets say you have table testT where name is unique to insure we have no doubles.
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
And you want to insert a new item with name test1 we set is as:
SET #newName = 'test1';
Then we need to check if it already exists in table:
SELECT #check:=COUNT(*) FROM testT WHERE name = #newName;
We do a count here to get true or false and save it as #check here so we can compare it later. This will result into 1 row as test1 already exists in table.
Next we do another selection to get the highest number of test* and store it as #number, this next query selects all tests and does a SUBSTRING after 4 latter's giving us all numbers after first 4 latter's. (99999999999) numbers actually just to be sure we don't miss any but in our case result is only "3" because that is last record "test3" in table.
SELECT
#number:= SUBSTRING(name,5,99999999999)
FROM testT;
Now we can do an insert:
INSERT INTO testT(name)
VALUES
(
IF(#check = "", #newName , CONCAT(LEFT(#newName,4),RIGHT(#number,1)+1)
)
);
This tries to insert our #newName into table under IF condition, and that is if our #check is empty then he will insert #newName, if not it will take word test out of string and append a highest #number from earlier and add + 1 too it.
So result for #newName = 'test1' is below. If you change this into #newName = 'test3' result wold be same new insert test4.
**Schema (MySQL v5.7)**
SET #newName = 'test1';
---
**Query #1**
SELECT * FROM testT
ORDER BY id;
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
| 3 | test4 |
---
And if you change it in ANY test* that number does not already exists it will insert it normally. In case below: #newName = 'test6'
SET #newName = 'test6';
**Query #1**
SELECT * FROM testT
ORDER BY id;
| id | name |
| --- | ----- |
| 1 | test1 |
| 2 | test3 |
| 3 | test6 |
This way an insert will always be made.
You can play with this here : View on DB Fiddle just by changing SET #newName = 'test6'
I am no expert and it took me couple of hours to figure this way out, as I wanted to know if this was even possible.
And I would appreciate if any other user can suggestion any other way or improve my method.

export phpList subscribers via sql in mysql database

For some reason, I am unable to export a table of subscribers from my phpList (ver. 3.0.6) admin pages. I've searched on the web, and several others have had this problem but no workarounds have been posted. As a workaround, I would like to query the mySQL database directly to retrieve a similar table of subscribers. But I need help with the SQL command. Note that I don't want to export or backup the mySQL database, I want to query it in the same way that the "export subscribers" button is supposed to do in the phpList admin pages.
In brief, I have two tables to query. The first table, user contains an ID and email for every subscriber. For example:
id | email
1 | e1#gmail.com
2 | e2#gmail.com
The second table, user_attribute contains a userid, attributeid, and value. Note in the example below that userid 1 has values for all three possible attributes, while userid's 2 and 3 are either missing one or more of the three attributeid's, or have blank values for some.
userid | attributeid | value
1 | 1 | 1
1 | 2 | 4
1 | 3 | 6
2 | 1 | 3
2 | 3 |
3 | 1 | 4
I would like to execute a SQL statement that would produce a row of output for each id/email that would look like this (using id 3 as an example):
id | email | attribute1 | attribute2 | attribute3
3 | e3#gmail.com | 4 | "" | "" |
Can someone suggest SQL query language that could accomplish this task?
A related query I would like to run is to find all id/email that do not have a value for attribute3. In the example above, this would be id's 2 and 3. Note that id 3 does not even have a blank value for attributeid3, it is simply missing.
Any help would be appreciated.
John
I know this is a very old post, but I just had to do the same thing. Here's the query I used. Note that you'll need to modify the query based on the custom attributes you have setup. You can see I had name, city and state as shown in the AS clauses below. You'll need to map those to the attribute id. Also, the state has a table of state names that I linked to. I excluded blacklisted (unsubscribed), more than 2 bounces and unconfirmed users.
SELECT
users.email,
(SELECT value
FROM `phplist_user_user_attribute` attrs
WHERE
attrs.userid = users.id and
attributeid=1
) AS name,
(SELECT value
FROM `phplist_user_user_attribute` attrs
WHERE
attrs.userid = users.id and
attributeid=3
) AS city,
(SELECT st.name
FROM `phplist_user_user_attribute` attrs
LEFT JOIN `phplist_listattr_state` st
ON attrs.value = st.id
WHERE
attrs.userid = users.id and
attributeid=4
) AS state
FROM
`phplist_user_user` users
WHERE
users.blacklisted=0 and
users.bouncecount<3 and
users.confirmed=1
;
I hope someone finds this helpful.

temp and main tables - mysql

I have a scenario where I need to insert the data into table temporarily and later on approval or confirmation, make it permanent. The data will be inserted by a user and approval or denial needs to be done by Super User.
What I think of now is to have two different but identical tables (temporary and main) and the user will insert the data into temp table. After confirmation of Super User, the data will be moved to main table. But the problem comes when a database contains very large number of tables then this process will become more complex.
EDIT : This implies to CREATE EDIT & DELETE commands.
Is there any simpler or better approach of doing this?
Please suggest.
Using a version table (related to comment):
The idea here is to have a version table; when your user changes a piece of information the new version is stored in this table along with the related ID.
Then all you need to do is join on the PersonID and select the most recent accepted version.
This means the user can make as many updates as they want but they won't show until the super user accepts them, it also means the data is never destroyed (stored in the version table) and they don't need to implement rollback as it's already there!
See: http://sqlfiddle.com/#!3/cc77f/4
People Table:
ID | Age Etc... (Info That Doesn't Change)
-----------------------
1 | 12
2 | 16
3 | 11
People Version Table:
VersionID | PersonID | Name | Approved
-----------------------
1 | 1 | Stevz | FALSE
2 | 1 | Steve | TRUE
3 | 2 | James | TRUE
4 | 3 | Jghn | FALSE
5 | 3 | John | TRUE
Example table SQL
CREATE TABLE People
(
id int identity primary key,
age int
);
CREATE TABLE PeopleVersion
(
versionId int identity primary key,
peopleId int,
name varchar(30),
approved varchar(30)
);
Example Query
SELECT * FROM People p
INNER JOIN PeopleVersion v ON p.id = v.peopleID
WHERE v.approved = 'TRUE'
ORDER BY versionId DESC
A further insight:
You could even have three states of Approved; null meaning no admin has chosen yet, TRUE meaning it was accepted and FALSE meaning it was rejected
You could show the user the most recent from null and true, show the admin all three and show the other users of the site only versions that were true
Old Comments
Could you just add a field called approved to the table and then hide anything without the approval flag set to TRUE?
It could default to FALSE and only the super user would be able to see items with the flag set to FALSE
E.g.
Name | Age | Approved
-----------------------
Steve | 12 | FALSE
James | 16 | TRUE
John | 11 | FALSE
The user would only see James, but the SuperUser would see all three listed
Alternatively using your temporary and main tables is the other way of looking at this problem, though this may lead to problems as everything get's larger
The easiest approach is a flag within the table marking an entry either approved or not-yet approved.
Then just change the retrieving logic to only show entries where that flag is set to approved.

MySQL query to search for all records against field with comma separated values

I have 2 sql tables
Table name: agents contains a records with a coloumn AgentID
Table named: vacancies is the one with the data ans is being dislayed.
Table named vacancies has vacancies.Agents which contains values simmilar to this
VacanyID Company position CTC Candidates Agents
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FBVAC001 | HDFC | Branch Manager | 4.5 | FBCAN001,FBCAN002| Agent3,Agent4
FBVAC003 | TBNH | Branch Manager | 4.5 | FBCAN004,FBCAN005| Agent2,Agent4
FBVAC005 | MMNT | Branch Manager | 4.5 | FBCAN008,FBCAN006| Agent3
FBVAC008 | LCFC | Branch Manager | 4.5 | FBCAN009,FBCAN023| Agent3,Agent4
FBVAC008 | KOTC | Branch Manager | 4.5 | FBCAN009,FBCAN023| Agent5,Agent4
I want to run a query that will return only those records that contain the value that corresponds to agents.AgentID from table name agents. This is the query so far but all it returs are those records that do not have more than one value in vacancies.Agents
for example if the value being searched for is Agent3 it should return rows1,3 and 4 instead it only returns row 3.
SELECT
vacancies.VacancyID,
vacancies.Company,
vacancies.`Position`,
vacancies.CTC,
vacancies.Candidates,
vacancies.Agents
FROM vacancies
, agents
WHERE (FIND_IN_SET(vacancies.Agents,agents.AgentID) <> 0)
How can this be resolved?
I believe you have your parameters backwards in FIND_IN_SET. The set should come second
FIND_IN_SET(agents.AgentID, vacancies.Agents)
More Info: http://www.bitbybit.dk/carsten/blog/?p=162
Also, if you are wanting to see only a specific agent, you need to filter for that as well, otherwise you're getting every possible combination of agent and matching vacancies (hence the duplicate rows):
AND Agents.AgentID = 'Agent3'
Demo: http://www.sqlfiddle.com/#!2/b4dcb/3
SELECT
vacancies.VacancyID,
vacancies.Company,
vacancies.`Position`,
vacancies.CTC,
vacancies.Candidates,
vacancies.Agents
FROM vacancies,
agents
WHERE (select
agents.agentid,
vacancies.agentid
from agents
left join vacancies
on vacancies.agentid = agents.agentid)
and agents.agentid = 'Agent3'

Need to insert CSV values in MySQL column to another table

I have a CSV file containing user information:
'Arlington', '1,3,5,7,9'
'StackExchange', '2,3'
And I will need the above information imported like this:
"User" table:
id | name
1 | 'Arlington'
2 | 'StackExchange'
"User groups" table:
id | user_id | group_id
1 | 1 | 1
2 | 1 | 3
3 | 1 | 5
4 | 1 | 7
5 | 1 | 9
6 | 2 | 2
7 | 2 | 3
What's the easiest way to do this? I have imported the data with a temp column holding the CSV values:
id | name | tmp_group_ids
1 | 'Arlington' | '1,3,5,7,9'
2 | 'StackExchange' | '2,3'
I am thinking if I import it this way, I will know exactly what id gets assigned for the user (the id column in the users table is auto_increment), and so I can use that id as user_id for the "user groups" table.
But now how do I get values from tmp_group_ids into the "User groups" table?
Would appreciate any help! Thanks!
the easy way would be a php or perl script.
You can use the MySQL SUBSTRING() function to split the string and insert the different values into the table. You can do this by writing a function or using a stored procedure.
I had recently a similar problem, I used the function SUBSTRING_INDEX(str,delim,count), using "," as delimiter
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring-index
INSERT INTO tableUserGroup (userid, groupid)
SELECT
t1.id
, substring_index(t1.tmp_group_ids,',',2)
, substring_index(t1.tmp_group_ids,',',3)
FROM table1 t1
First, insert the names into the User table - with id autonumber, this will work:
INSERT INTO User
(name)
SELECT DISTINCT
name
FROM TempTable
Then:
--- Create a "numbers" table:
CREATE TABLE num
( i INT PRIMARY KEY
) ;
--- Populate it with numbers:
INSERT INTO num
(i)
VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
Then, you can use FIND_IN_SET() function which is handy for this situation (splitting comma-separated fields), like this:
INSERT INTO User_Groups
(user_id, group_id)
SELECT
u.id AS user_id
, num.i AS group_id
FROM User AS u
JOIN TempTable AS t
ON t.name = u.name
JOIN num
ON FIND_IN_SET(num.i, t.tmp_group_ids) > 0