ruby code to direct all users to a particular location instead of multiple locations and delete duplicates - mysql

I am having a User model and a Location Model. Each user belongs to a particular location in the Location model.
I am having duplicate locations in the Location table.
and User belongs to Location.
how can i remove duplicate rows in the location table and keep one row and make all users belong to that single row using ruby. Both the tables are connected through location_ID attribute.
I tried to do this through migration:
def dedupe(model, *key_attrs)
model.select(key_attrs).group(key_attrs).having('count(*) > 1').each { |duplicates|
dup_rows = model.where(duplicates.attributes.slice(key_attrs)).to_a
# the first one we want to keep right?
first_one = dup_rows.shift #stored the first one
dup_rows.each{ |double| double.destroy } # duplicates can now be destroyed
}
end
But there is foreign key constraint of User not letting the migration to run. How can I achieve this?
Current Models are :
User
user_id name location_id
1 tim 1
2 adam 2
3 Joy 3
Location
location_id name
1 NewYork
2 NewYork
3 NewYork
Expected Ouput:
User
user_id name location_id
1 tim 1
2 adam 1
3 Joy 1
Location
location_id name
1 NewYork

Kinda ugly, but you can use a subquery:
First, grab the first occurrence of all records which are duplicates;
original_duplicate_locations = Location.select("MIN(id) AS id, name, user_id").group(:name, :user_id).having("COUNT(id) > 1")
The extra duplicates are defined as locations having the same name, and user_id but not the same id:
duplicates_not_including_originals = Location.joins("JOIN (#{duplicates.to_sql}) dupes ON locations.name = dupes.name AND locations.user_id = dupes.user_id AND locations.id <> dupes.id")

Hey you can try this way:
1)First Update all entries with location first entry in location table using
User.joins(:location).update_all("location_id = select id from locations as l2 where l2.name = locations.name limit 1")
Note: you can also use order by id here if sub query not return first entry from table.
2)Destroy All entries from location table excluding first entry-
Before this make sure all your data get updated with first entry in location table properly means first id of repeated location is updated or not. because after deletion it is not possible to recover your data again. then just destroy all your repeated entries excluding first entry using
Location.where("id not in (?)", Location.select("min(id) as id").group("name").map(&:id)).destroy_all

Related

Sql SELECT query just shows 1 row

So im trying to get a table that shows 3 activities which have the id's of 6,7,8 and they must be from a specific country. It should show their names and the number of times they appear in the person_activity_interval but the table i get is only 1 row with the name of 1 activity and the count of all the activities that are listed. If i remove other 2 activities it gets me the correct name and count but i need a table with all 3. Do i need to use something like join or union?
SELECT name,count(activity_id)
FROM activity,person_activity_interval
WHERE oib IN (SELECT oib
FROM person
WHERE living_id IN (SELECT id
FROM living
WHERE country= "Poland"))
AND ((activity_id=8 AND id =8) OR (activity_id=7 AND id =7) OR (activity_id=6 AND id =6));

Fetch rows either with one matching condition or all rows if no matching rows

I have a simple table
**targeted_url_redirect targeted_countries msg_type non_targeted_url**
http://new.botweet.com india,nepal,philippines NEW http://twisend.com
http://expapers.com United States,Canada OLD http://all.twisend.com
https://tweeasy.com india,england OLD http://all.twisend.com
I receive traffics on my website followerise.com and I want to redirect users to specific urls based on their countries as defined in the above table. I am able to write query to get rows for the users who coming from the countries that are target stored in my database. But I am looking for a solution to get all the rows if the targeted_countries condition not return any rows.
I written below queries.
SELECT * FROM tweeasy_website_redirection
WHERE message_type='OLD'
AND targeted_countries LIKE '%#country%'
This query gives me desired rows if visitor coming from the countries india,england,United States,Canada
But I want all rows (2nd and 3rd) should be fetched if a user coming from the countries not specified in targeted_countries column.
Also let me know if I need to restructure this table into 2 or more tables to get desired result.
One option uses not exists:
SELECT t.*
FROM tweeasy_website_redirection t
WHERE
t.message_type = 'OLD'
AND (
t.targeted_countries LIKE '%#country%'
OR NOT EXISTS (
SELECT 1
FROM tweeasy_website_redirection t1
WHERE t1.targeted_countries LIKE '%#country%'
)
)
When it comes to the structure of your table: one design flaw is to store list of values as CSV list. You should have two separate tables: one to store the urls, and the other to store the 1-N relationship between urls and countries. Something like:
table "url"
id targeted_url_redirect msg_type non_targeted_url
1 http://new.botweet.com NEW http://twisend.com
2 http://expapers.com OLD http://all.twisend.com
3 https://tweeasy.com OLD http://all.twisend.com
table "url_countries"
url_id country
1 india
1 nepal
1 philippines
2 united states
2 canada
3 india
3 england
select * from tweeasy_website_redirection
where targeted_countries not in (SELECT targeted_countries FROM stack WHERE targeted_countries LIKE '%#country%')

how to select specific rows in some condition

I tried to write a query that selects rows with steps that both user 1 and user 2 did, with combined number of times they did the step (i.e., if user 1 did step 1 3 times and user 2 did 1 time then the count should show 4 times.)
when I put condition as user_id=1, user_id=2 there is no error but it return nothing, when it should return some rows with values.
there is table step, and step taken
and table step has column id, title
table step_taken has column id, user_id(who performs steps), step_id
i want to find step that both of two user whose id 1,2 did
and also want to have the value as count added up how many times they performed that step.
for example if user id 1 did step named meditation 2 times,
and user id 2 did step named meditation 3 times,
the result i want to find should be like below ;
------------------------------
title | number_of_times
------------------------------
meditation| 5
------------------------------
here is my sql query
select title, count(step_taken.step_id)as number_of_times
from step join step_taken
on step.id = step_taken.step_id
where user_id = 1 and user_id=2
group by title;
it returns nothing, but it should return some rows of step both user1 and user 2 did.
when i wrote same thing only with user_id=1 or user_id=2, it shows selected information
how can I fix my code so it can show the information I want to get?
thanks in advance :)
user_id cannot be 1 and 2 at the same time. You need a second user table. Then join those on your criteria and count:
select title, count(u1.id) + count(u2.id) as number_of_times
from step u1 join step u2
on u1.id = u2.id
where u1.user_id = 1 and u2.user_id=2
group by title;
note: cannot tell what table title is in, or the purpose of step_taken was as step.id is identical.

Select all values from one table, check another table to see related columns and fetch more values

I really dont know how to phrase my question, probably why google is not giving me results that i need, but am going to try.
I have two tables, required_files table and submitted_files table. I have a page where i want to display to a user all required files for submission and show which files he/she has submitted.
Required files table is as follows:
file_id file_name mandatory
1 Registration Certificate 0
2 KRA Clearance 1
3 3 Months Tax returns 0
4 Business Permit 1
5 Tour Permit 1
6 Country Govt Operating License 0
7 Certificate of good Conduct 0
file_id is unique, mandatory column is binary value to state whether the file is mandatory before registration or not.
submitted files table is a follows
file_id user_id file_required_id original_file_name file_name_on_server submission_date
1 2 2 KRA_Form.docx 0a10f5291e9bcb6a345ac7a8f5705b8a.docx 2016-11-01
2 2 3 Tax_returns.docx 9f04361013df7e25235a03c506f347ed.docx 2016-11-03
3 3 3 Taxes.docx 86aea74cc87fb669510d9d4c488cbcf8.docx 2016-11-04
file_id is unique AI value, user_id col is unique value of the current user logged in, file_required_id column is related to files_required.file_id column
When fetching the values i already have a user_id (in this case, lets use user_id = 2) Now i want to fetch all values of files_required table and check on files submitted table for files that user_id = 2 meaning user has submitted the files.
my sql query is as follows
SELECT files_required.*, submitted_files.* FROM submitted_files
RIGHT JOIN files_required ON files_required.id = submitted_files.file_required_id
WHERE submitted_files.user_id = 2
This gives me two rows only where the user_ids matched but i want the entire files_required table values and show which files the user has submitted. Someone Kindly assist.
In the meantime, i am fetching files_requied table first then looping through the other table using a php script to look for submitted files for the given user. it works but its not what i wanted and is cumbersome and a rookie move.
Try having user_id condition in RIGHT JOIN itself like below query
SELECT files_required.*, submitted_files.*
FROM submitted_files
RIGHT JOIN files_required ON files_required.id = submitted_files.file_required_id
AND submitted_files.user_id = 2
You want this.
SELECT submitted_files.user_id, files_required.*, submitted_files.*
FROM submitted_files
RIGHT JOIN files_required ON files_required.id =
submitted_files.file_required_id
Don't put the where condition on userid as it will filter out the data just for that user. You want all the records and user should also be seen. Just put the user_id in the select statement.

How to SELECT MySQL 1-to-LAST on 1-to-Many Relationship

I have 2 Tables -- Table 1 is a master file and Table 2 is an activity file.
The relationship is 1-to-Many.
I am producing a report and all I want to return is every master file row joined to only the last activity row for the related master id.
I am unsure on how to request the last activity row. My code below returns every activity row (rightfully so).
Thank you for your help.
SELECT *
FROM master_file AS master
INNER JOIN activity_file AS activity ON activity.id = master.id
ORDER BY master.display_name
The activity file has a column called entry_date. It is a date and time stamp recording every activity. I simply want to select the last entry_date.
For example:
Table 2 - Activity looks like this
ID ACTIVITY ENTRY_DATE
1 Update 2012-08-01 09:00:00
1 Edit 2012-08-01 13:45:15
3 Create 2012-07-15 10:09:52
3 Delete 2012-07-22 23:02:00
3 Add 2012-08-05 04:33:00
4 Edit 2012-08-03 15:12:00
One standard way to solve this is to create an inline view that finds the last entry_date per ID.
SELECT *
FROM master_file AS master
LEFT JOIN activity_file AS activity ON activity.id = master.id
LEFT JOIN (select id , max(entry_date) entry_date
From activity_file
group by id) last_activity
ON activity_file.id = last_activity.id
and activity_file.entry_date= last_activity.entry_date
ORDER BY master.display_name
The one problem with this approach is that you may have more than one record with max(entry_date) for a given id. You'll either need to have your business rules handle this (e.g. simply display more than one record for that case) or you'll need to figure out a tie breaker. The last thing you want is to make it non-deterministic