Update Based on a common value where there are multiple matches - mysql

I've got two tables (MySQL database), one called cities (that has columns 'state_id' and 'stateAB'--state_id is the row I would like to fill, stateAB is the 2-letter code of the state--I want this to serve as the key value).
I have another table called states (that has columns 'id' [this is the value that I want to go into the 'state_id' field of 'cities'], and a 'title' field [2-letter state codes] to be the common-key value).
I wanted to use a simple:
UPDATE cities SET state_id=(SELECT id FROM states WHERE states.title=cities.stateAB)
With the idea being that state_id will be set to the id that is returned where the 2-letter codes match.
The problem is that the following is returned:
#1242 - Subquery returns more than 1 row
I assume this is because there are more than one time per state that the codes match, for the simple reason that there are multiple cities per state (and they all have the same state/codes).
I'm not sure how to change this to make it work--I'm sure it's something obvious I'm just missing, but I don't know how to deal with the issue.

This is your query:
UPDATE cities
SET state_id = (SELECT id FROM states WHERE states.title = cities.stateAB);
You are getting the error because states has duplicates in the title column. You can find these by running:
select title, count(*) as numdups
from states
group by title
having count(*) > 1;
You may not care about the duplicates, happy to select just one id (consistently) when there is a match. If so, you can do:
UPDATE cities
SET state_id = (SELECT MIN(id) FROM states WHERE states.title = cities.stateAB);

Related

sql: selecting a value in an attributes table

I have a database with the following schema:
thing
id
id_thing_type
thing_attribute
id
name
id_thing_type
thing_attribute_value
id_thing_attribute
value_date
Thing has many Thing_Attributes joined on thing.id_thing_type = thing_attribute.id_thing_type
Thing_Attributes have one Thing_Attribute_Value joined on thing_attribute.id = thing_attribute_value.id_thing_attribute
I am trying to write a query that will return the value of a specific attribute (with a certain name) for a specific thing record (with a certain id). thing.id represents a unique row.
Said another way, thing_attribute and thing both have an id_thing_type. These tables need to be joined on id_thing_type = id_thing_type. Think of this as each type of thing has its own unique set of thing_attributes. The task is to find the value of a specific attribute of a specific thing.
This is what I have so far, however it returns many rows:
SELECT t.id, tav.value_date
FROM thing_attribute_value tav
JOIN thing_attribute ta
ON tav.id_node_attribute = ta.id
JOIN thing t
ON ta.id_thing_type = t.id_thing_type
WHERE ta.name = 'Birth Date'
AND t.id = '123'
Here is an example result. As you can see, many rows are returned, all with the same id for thing, but with different dates.
123,2015-12-02
123,2014-11-02
123,2013-07-11
123,2014-03-12
etc....
So, as discussed in the comments to my original answer:
Thing has a Thing_Type_Id Column.
And Thing_Attribute has a Thing_Type_Id Column.
For which there is a 1::1 relationship.
Thing_Attribute has a Thing_Attribute_Value_Id column.
And Thing_Attribute_Value has an Id column.
For which there is a 1::Many relationship.
This is what is causing your query to fail. The error is actually in your data relationships, not the query.
Let's try to piece this together:
Thing
- needs a unique id
- can have any number of other columns
- will have many attributes, but this column will not be in this table
Thing_Attributes
- needs a unique id
- needs a Thing id (fk to Thing)
- needs a Type id (fk to Thing_Attribute_Type)
- needs a Value
Thing_Attribute_Value - can go away - Replace it with a lookup for Type
Thing_Attribute_Type
- needs unique id
- needs Value
With this relational structure you can have many Attributes for each Thing
You use an id field for Attribute Type so you are not repeating a strings.
Use a lookup that gets an Attribute_Type value based on the Id.
This is an overhaul to your current relationship model, but with your current one you cannot isolate a given attribute value to a given Thing, which I think was at least one of the goals in building your Thing objects.

ORDER BY # of rows with same option ID from different table

I've made a voting script which already works, but I wanted to practice some MySQL to try and do sorting/filtering of the results via SQL queries instead of getting an entire table as an array and working with that using loops.
I've ran into an issue with sorting the options of a vote based on the amount of times it was voted on. My DB has 3 tables related to this script:
vote_votes - which contains the cast votes, one row per vote cast
vote_options - which contains the possible options for every vote
vote_list - which contains the list of votes with title, type etc.
My original script just got all the options that matched the currently visited vote's ID using
SELECT * FROM vote_options WHERE vote_options.vid = $voteID
then counted the rows matching the option's unique ID inside vote_votes in an array, then sorted it based on the amount of rows with a custom sorting function.
I want to do the same in one query, and I think it's possible, I just don't know how. Here's my current SELECT statement:
SELECT
options.optid as id,
options.value as value
FROM vote_options options
WHERE vid = {$vote['vid']};");
Basically, inside vote_votes, each entry has a unique entryid and an optid column, and I want to add it to the query in a way that these entries are counted as WHERE vote_votes.optid = options.optid (Option IDs are unique, so no need to also look for vote ID).
I was hoping this would work, but it's obviously wrong. This is the closest I got before giving up and asking a question here.
SELECT
options.optid as id,
options.value as value
FROM vote_options options
WHERE vid = {$vote['vid']}
ORDER BY (
SELECT COUNT(*)
FROM vote_votes
WHERE vote_votes.optid = options.optid
) DESC;
I've found the solution, it was just a matter of moving the SELECT in brackets to the correct place:
SELECT
options.optid as id,
options.value as value,
options.vid as voteid,
(
SELECT COUNT(*)
FROM vote_votes votes
WHERE votes.optid = options.optid
) as votes
FROM vote_options options
WHERE options.vid = {$vote['vid']}
ORDER BY votes DESC;

What's the mysql syntax to pull data on the fly

I have a table with a bunch of orders... one of the columns is order_status. The data in that column ranges from 1 to 5. Each number relates to a name, which is stored in another table that relates that number to the respective name.
SELECT order_id , order_status FROM tablename1
The above would just return the numbers 1,2,3,4,5 for order status. How can i query within the query on the fly to replace these numbers with their respective names.
Also, what's the term used to describe this. I'd Google it if i knew what the appropriate term was.
Each number relates to a name, which is stored in another table that
relates that number to the respective name.
JOIN it with the other table:
SELECT
t.order_id,
s.StatusName
FROM tablename1 AS t
INNER JOIN the statusesTable AS s ON t.order_status = s.status_id;

Update table based on other 2 related tables

I have a strange problem. I got some data for cities, regions and countries in CSV format and imported them into MySQL tables.
I have 3 tables and their fields
1. City : id, name, country_code, region_number
2. Region : region_number, country_code, name
3. Country : country_code, name
Now things get a little complicated, as I added an auto-generated id column to the region table, so the region x for country y would be unique.
The thing is: Now i am trying to update city field region_number to hold this unique value (the new id column in region) so I can have relations city->region.
The relation region->country or country->region is OK.
Is it possible to write an update query that would update city region_code (or fill some new column, eg. region_id) with correct values?
If not an query, what could I use to get the correct values into the cities table?
I have arround 3 million records!
If I understant correctly, I think you are looking for something like this:
UPDATE
City inner join Region
on City.country_code = Region.country_code
and City.region_number = Region.region_number
SET
City.new_column = Region.id
However, since there's a relation already between City and Region, I am not sure this is the right thing to do, since it will make the table not normalized.
Now i am trying to update city field region_number to not hold this unique value
The only way you can do this is if the region_number uniquely identifies each region - and if that's already the case then you are wasting your time by creating redundant references. Although frankly, if these really are your table structures, there's no reason for using surrogate keys. And if there's no reason for using surrogate keys then the region and country table are redundant.

What is wrong with this MySQL Query? need help to understand

I have 4 tables namely,
countries, states, cities, areas,
apart from countries table the rest three(states,cities,areas) contains country_id foreign key.
i wanted to return the total number of count of country_id combined in three tables for which i used jon_darstar's solution, here is the code i am using.
SELECT COUNT(DISTINCT(states.id)) + COUNT(DISTINCT(cities.id)) + COUNT(DISTINCT(areas.id))
FROM states
JOIN cities on cities.country_id = states.country_id
JOIN areas on areas.country_id = states.country_id
WHERE states.country_id IN (118);
the above code works perfectly fine although i am unable to understand the code properly, mainly the first line i.e
SELECT COUNT(DISTINCT(states.id)) + COUNT(DISTINCT(cities.id)) + COUNT(DISTINCT(areas.id))
Question 1 : doesn't that select the
primary id of the three tables
states,cities and areas and make the
count? i know this is not happening
from the result i am getting then what
is actually happening here?
However if i remove the DISTINCT from the query string it shows me a different result i.e a count of 120 whereas actually it should be 15(this is the count number of country_id in all three tables).
Question 2 : What is happening if i
use DISTINCT and remove DISTINCT?
isn't DISTINCT supposed to remove any
duplicate values. where is duplication
happening here?
thank you..
For an example, if in a country A(having primary id a.id=118),there is State B(having primary id b.id),inside that state there is City C(having primary id c.id), In city C there's Area D(having primary id d.id),E(having primary id e.id),F(f.id).lets visualize the query result in a database table.
C St Ct Ar
A->B->C->D
A->B->C->E
A->B->C->F
(Here C=Country,St=States,Ct=Cities,Ar=Areas)
Now just think what happens when you do count on above table to get total number of States within Country A without distinct.The result is 3,this way the Number of Cities is 3 and areas is 3,total 9.Because without distinct you're getting duplicate values in which you're not interested.
Now,if you use distinct count you'll get correct result cause here distinct states under
country A is 1,City is 1 and Areas is 3,total:5(excluding duplicate values)..
Hope this works!
!!Design Issue!!!
Like to add something:From your database design,i can see that you're using country id as a reference for countries from country table(to states,areas and cities) then joining states and cities then states and areas (by their country id)don't you think it's creating cross join?.Better design choice is at areas table keep foreign key of city,this way go bottom up like in city keep states and in states keep country.Or make a table for Areas where you are keeping Countries,States,Cities foreign key and areas primary key.