I am saving company information in a database, and if repeat information is found, I want to update the overlapping rows. Some of the supported fields are emails, phone numbers, organization names, and latitude/longitude positions. One of the obvious issues I've had to deal with, however, is knowing whether or not an organization is a duplicate of an already saved one. Consequently, I came up with some basic combinations of unique information that distinguishes one company from another:
- phone number + organization_names
- organization_names + location
- email hash + website hash
- phone + email hash
- phone + website hash
- email hash + location
- email hash + organization name
- website hash + location
- website hash + organization_name
My workflow, as of now is as follows:
- Determine if any of the above unique combinations are satisfied by the new information
- Loop through each combination and create an MySQL query to check the database for duplicate entries
Use PHP's
multi_query
to run semicolon separatedselect
statements for the above queries. These queries look like this:SELECT id, jaro_winkler_similarity(normalized, "ORGANIZATION_NAME") AS organization_name_similarity0 FROM profiles LEFT JOIN phones USING(id) LEFT JOIN (SELECT id, normalized FROM organization_names WHERE normalized LIKE "%ORGANIZATION%" OR normalized LIKE "%NAME%" AS likeMatches USING(id) WHERE (number="6316870100" OR number="123") HAVING organization_name_similarity0 > 85; SELECT id, jaro_winkler_similarity(normalized, "ORGANIZATION_NAME") AS organization_name_similarity0 FROM profiles LEFT JOIN (SELECT id, normalized FROM organization_names WHERE normalized LIKE "%ORGANIZATION%" OR normalized LIKE "%NAME%" AS likeMatches USING(id) LEFT JOIN locations USING(id) WHERE normalized_house_number="110" AND normalized_street_name="WASHINGTON" AND zip="00501" HAVING organization_name_similarity0 > 85; SELECT id, jaro_winkler_similarity(normalized, "ORGANIZATION_NAME") AS organization_name_similarity0, (3959 * acos(cos(radians(40.82127)) * cos(radians(latitude)) * cos(radians(longitude) - radians(-73.051872)) + sin (radians(40.82127)) * sin(radians(latitude)))) AS coordinate_distance0 FROM profiles LEFT JOIN (SELECT id, normalized FROM organization_names WHERE normalized LIKE "%ORGANIZATION%" OR normalized LIKE "%NAME%" AS likeMatches USING(id) LEFT JOIN locations USING(id) HAVING organization_name_similarity0 > 85 AND coordinate_distance0 < 0.1; SELECT id FROM profiles LEFT JOIN emails USING(id) LEFT JOIN websites USING(id) WHERE (hash="93e6b0eff1d85b8b177fc44ce66cd1871dcb89b8") AND (hash="433833d572dc47f8576468a384ef8539a15f4031"); SELECT id FROM profiles LEFT JOIN phones USING(id) LEFT JOIN emails USING(id) WHERE (number="6316870100" OR number="123") AND (hash="93e6b0eff1d85b8b177fc44ce66cd1871dcb89b8"); SELECT id FROM profiles LEFT JOIN phones USING(id) LEFT JOIN websites USING(id) WHERE (number="6316870100" OR number="123") AND (hash="433833d572dc47f8576468a384ef8539a15f4031"); SELECT id FROM profiles LEFT JOIN emails USING(id) LEFT JOIN locations USING(id) WHERE (hash="93e6b0eff1d85b8b177fc44ce66cd1871dcb89b8") AND normalized_house_number="110" AND normalized_street_name="WASHINGTON" AND zip="00501"; SELECT id, (3959 * acos(cos(radians(40.82127)) * cos(radians(latitude)) * cos(radians(longitude) - radians(-73.051872)) + sin (radians(40.82127)) * sin(radians(latitude)))) AS coordinate_distance0 FROM profiles LEFT JOIN emails USING(id) LEFT JOIN locations USING(id) WHERE (hash="93e6b0eff1d85b8b177fc44ce66cd1871dcb89b8") HAVING coordinate_distance0 < 0.1; SELECT id, jaro_winkler_similarity(normalized, "ORGANIZATION_NAME") AS organization_name_similarity0 FROM profiles LEFT JOIN emails USING(id) LEFT JOIN (SELECT id, normalized FROM organization_names WHERE normalized LIKE "%ORGANIZATION%" OR normalized LIKE "%NAME%" OR normalized LIKE "%firm%" OR normalized LIKE "%pc%") AS likeMatches USING(id) WHERE (hash="93e6b0eff1d85b8b177fc44ce66cd1871dcb89b8") HAVING organization_name_similarity0 > 85; SELECT id FROM profiles LEFT JOIN websites USING(id) LEFT JOIN locations USING(id) WHERE (hash="433833d572dc47f8576468a384ef8539a15f4031") AND normalized_house_number="110" AND normalized_street_name="WASHINGTON" AND zip="00501"; SELECT id, (3959 * acos(cos(radians(40.82127)) * cos(radians(latitude)) * cos(radians(longitude) - radians(-73.051872)) + sin (radians(40.82127)) * sin(radians(latitude)))) AS coordinate_distance0 FROM profiles LEFT JOIN websites USING(id) LEFT JOIN locations USING(id) WHERE (hash="433833d572dc47f8576468a384ef8539a15f4031") HAVING coordinate_distance0 < 0.1; SELECT id, jaro_winkler_similarity(normalized, "ORGANIZATION_NAME") AS organization_name_similarity0 FROM profiles LEFT JOIN websites USING(id) LEFT JOIN (SELECT id, normalized FROM organization_names WHERE normalized LIKE "%ORGANIZATION%" OR normalized LIKE "%NAME%" AS likeMatches USING(id) WHERE (hash="433833d572dc47f8576468a384ef8539a15f4031") HAVING organization_name_similarity0 > 85;
If a match is found, grab the associated company id and add new information
- If no matches are found, add a new company id and add the new information to the database
This, to me, seems incredibly superfluous but more importantly is slow. I'd like to condense my MySQL queries (I'm slightly ashamed by them, there has to be a better way to do this) into something more succinct, but I can't think of an appropriate way to do so. Similarly, I can't break if a match is found or a match isn't found, because data might be saved using a different unique combination which needs to be checked as well.