I have users represented in a user table and need to design a model to associate them with state/cities/districts that they choose:
On the database side,
Each user will be associated with 1 state, 1 city and a number of districts within that state/city combination. For instance, User A can choose to be associated with "NY" and "Brooklyn" and any X number of districts in "Brooklyn" (or none).
On the view side,
I'd like to present the district choices with checkboxes so they should be able to be pulled from the database field with simple_form in Rails pretty easily.
The design of the database should make it easy to query for the user and get the associated state / city and district relations that the user has chosen.
One idea I have is to simply have a one-to-many field for districts and a district table listing all the different districts. However, is there a way to enforce that the districts have to be valid for the city/state combination on the backend using validate?
Any tips would be appreciated.
Below I have outlined the database schema I would use based on the information you have given.
Every city belongs to exactly one state.
cities
id unsigned int(P)
state_id unsigned int(F states.id)
name varchar(50)
+----+----------+---------------+
| id | state_id | name |
+----+----------+---------------+
| 1 | 33 | New York City |
| .. | ........ | ............. |
+----+----------+---------------+
See ISO 3166 for more information. You didn't ask for countries but it's trivial to add them...
countries
id char(2)(P)
iso3 char(3)(U)
iso_num char(3)(U)
name varchar(45)(U)
+----+------+---------+---------------+
| id | iso3 | iso_num | name |
+----+------+---------+---------------+
| ca | can | 124 | Canada |
| mx | mex | 484 | Mexico |
| us | usa | 840 | United States |
| .. | .... | ....... | ............. |
+----+------+---------+---------------+
Every district belongs to exactly one city.
districts
id unsigned int(P)
city_id unsigned int(F cities.id)
name varchar(50)
+----+---------+-----------+
| id | city_id | name |
+----+---------+-----------+
| 1 | 1 | The Bronx |
| 2 | 1 | Brooklyn |
| 3 | 1 | Manhattan |
| .. | ....... | ......... |
+----+---------+-----------+
See ISO 3166-2:US for more information. Every state belongs to exactly one country.
states
id unsigned int(P)
country_id char(2)(F countries.id)
code char(2)
name varchar(50)
+----+------------+------+----------+
| id | country_id | code | name |
+----+------------+------+----------+
| 1 | us | AL | Alabama |
| .. | .......... | .... | ........ |
| 33 | us | NY | New York |
| .. | .......... | .... | ........ |
+----+------------+------+----------+
Based on your information a user belongs to exactly one city. In the example data Bob is associated with New York City. By joining tables you can very easily find that Bob is in New York state and the country of United States.
users
id unsigned int(P)
username varchar(255)
city_id unsigned int(F cities.id)
...
+----+----------+---------+-----+
| id | username | city_id | ... |
+----+----------+---------+-----+
| 1 | bob | 1 | ... |
| .. | ........ | ....... | ... |
+----+----------+---------+-----+
Users can belong to any number of districts. In the example data Bob belongs to The Bronx and Brooklyn. user_id and district_id form the Primary Key which insures a user cannot be associated with the same district more than once.
users_districts
user_id unsigned int(F users.id) \_(P)
district_id unsigned int(F districts.id) /
+---------+-------------+
| user_id | district_id |
+---------+-------------+
| 1 | 1 |
| 1 | 2 |
| ....... | ........... |
+---------+-------------+
My database model does NOT enforce the rule that the districts a user belongs to must be in the city that user belongs to - in my opinion that logic should be done at the application level. If Bob moves from New York City to Baltimore I think all of his records should be deleted from the users_districts table and then add any new ones for his new city.
As for the user interface, I would have the user:
Select a country - this will auto-populate a drop down list of associated states.
Select a state - this will auto-populate a drop down list of associated cities.
Select a city - this will auto-populate a list of associated districts.
Allow the user to select any number of districts.
You will need some combination of database and application-level logic.
Here is how I would build the database fields:
users = id, <other user fields>, city_id
districts = id, <other district fields>, city_id
cities = id, name, state_id
states = id, name
And then in the application, set it up so that the user can type in one city and multiple districts, and can not edit the state (view only):
When the user types in a city - maybe through a autocomplete field - it automatically updates the read-only state field with the state of the city
When the user types in a district, list only the districts that have district.city_id == cities.id
If you don't want to restrict the district selection in the UI, you will need to enforce the district.city_id == cities.id check in your application, though I personally think that's less intuitive than doing it right in the front-end UI.
Indian States AND UT MySQL QUERY
INSERT INTO `states`
VALUES
(1,'Andhra Pradesh'),
(2,'Telangana'),
(3,'Arunachal Pradesh'),
(4,'Assam'),
(5,'Bihar'),
(6,'Chhattisgarh'),
(7,'Chandigarh'),
(8,'Dadra and Nagar Haveli'),
(9,'Daman and Diu'),
(10,'Delhi'),
(11'Goa'),
(12,'Gujarat'),
(13,'Haryana'),
(14,'Himachal Pradesh'),
(15,'Jammu and Kashmir'),
(16,'Jharkhand'),
(17,'Karnataka'),
(18,'Kerala'),
(19,'Madhya Pradesh'),
(20,'Maharashtra'),
(21,'Manipur'),
(22,'Meghalaya'),
(23,'Mizoram'),
(24,'Nagaland'),
(25,'Orissa'),
(26,'Punjab'),
(27,'Pondicherry'),
(28,'Rajasthan'),
(29,'Sikkim'),
(30,'Tamil Nadu'),
(31,'Tripura'),
(32,'Uttar Pradesh'),
(33,'Uttarakhand'),
(34,'West Bengal'),
(35,'Lakshadweep'),
(36,'Ladakh ');
Related
I used inheritance feature from Postgresql 9.6 to create some archive for huge amount of data.
Finally parent table looks like this
foo=# \d+ foo_data_sshcommand
Table "public.foo_data_sshcommand"
Column | Type | Modifiers | Storage | Stats target | Description
------------+--------------------------+-------------------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('foo_data_sshcommand_id_seq'::regclass) | plain | |
time | timestamp with time zone | not null | plain | |
command | text | not null | extended | |
success | boolean | not null | plain | |
session_id | integer | not null | plain | |
Indexes:
"foo_data_sshcommand_pkey" PRIMARY KEY, btree (id)
"foo_data_sshcommand_session_id_c8b38d68" btree (session_id)
Check constraints:
"partition_check" CHECK ("time" >= '2019-10-01 00:00:00+02'::timestamp with time zone) NO INHERIT
Foreign-key constraints:
"foo_data_sshcommand_session_id_c8b38d68_fk" FOREIGN KEY (session_id) REFERENCES foo_data_sshsession(id) DEFERRABLE INITIALLY DEFERRED
Child tables: arc_2019_01_foo_data_sshcommand,
arc_2019_02_foo_data_sshcommand,
arc_2019_03_foo_data_sshcommand,
arc_2019_04_foo_data_sshcommand,
arc_2019_05_foo_data_sshcommand,
arc_2019_06_foo_data_sshcommand,
arc_2019_07_foo_data_sshcommand,
arc_2019_08_foo_data_sshcommand,
arc_2019_09_foo_data_sshcommand,
arc_2019_foo_data_sshcommand
Every month it creates two more tables and it adds them to the archive. It is not nice process, because it must move overflowed data from parent table to new child table. But it is not the problem that I want to talk about. I am curious about question - How many tables can paricipate on inheritance of one parent table?
I have a table that looks like this:
Created at | Amount | Register Name
--------------+---------+-----------------
01/01/2019... | -150.01 | Front
01/01/2019... | 38.10 | Back
What is the best way to attach an ascending-by-date running total to each record which applies only to the register name the record has? I can do this in Ruby, but doing it in the database will be much faster as it is a web application.
The application is a Rails application running Postgres 10, although the answer can be Rails-agnostic of course.
Use the aggregate sum() as a window function, e.g.:
with my_table (created_at, amount, register_name) as (
values
('2019-01-01', -150.01, 'Front'),
('2019-01-01', 38.10, 'Back'),
('2019-01-02', -150.01, 'Front'),
('2019-01-02', 38.10, 'Back')
)
select
created_at, amount, register_name,
sum(amount) over (partition by register_name order by created_at)
from my_table
order by created_at, register_name;
created_at | amount | register_name | sum
------------+---------+---------------+---------
2019-01-01 | 38.10 | Back | 38.10
2019-01-01 | -150.01 | Front | -150.01
2019-01-02 | 38.10 | Back | 76.20
2019-01-02 | -150.01 | Front | -300.02
(4 rows)
This is not a homework question. I am trying to learn more.
I have the following entities with attributes
Manufacturer {name} //Store Manufactueres
Model {manufacturer_id, name} //Store Models
Tint {manufacturer_id, model_id, front, side, rear} //Store measurements
I have the follow data in my Tint entity. Alphabets stands for different manufacturer name and models.
Manufacturer | Model | Front | Side | Rear |
-------------+-------+-------+------+-------
A | AD | 10 | 10 | 10 |
B | AB | 10 | 10 | 10 |
A | AA | 10 | 10 | 10 |
A | AC | 10 | 10 | 10 |
B | AA | 10 | 10 | 10 |
A | AB | 10 | 10 | 10 |
When I print it out in view, I would like to have it sorted based on Manufacturer name and then Model. So the result will be as below. The name of the Manufactures will be sorted alphabetically, then Models.
Manufacturer | Model | Front | Side | Rear |
-------------+-------+-------+------+-------
A | AA | 10 | 10 | 10 |
A | AB | 10 | 10 | 10 |
A | AC | 10 | 10 | 10 |
A | AD | 10 | 10 | 10 |
B | AA | 10 | 10 | 10 |
B | AB | 10 | 10 | 10 |
I have setup the model to make sure Manufacturer and Model is a distinct pair of values.
My question is since I am referencing using manufacturer_id and model_id, how can I get the name of the Manufacturer and Model from Manufacturer and Model table.
In my tints_controller.rb, I have #tints = Tint.all.order(:manufacturer_id). However, it will only sort based on the manufacturer_id (as in numbers) instead of the name of the manufacturer.
I know that I can do it in SQL way (SELECT, FROM, WHERE) in RoR model. However, I would like to know is it possible to use ActiveRecord to sort the data based on their name.
If I understand correctly, you have 3 models, Tint, Manufacturer and Model. I am assuming you have the appropiate has_many and belongs_to associations setup correctly.
Tint.rb
belongs_to :workspace
Manufacturer.rb
has_many :models
has_many :tints, through: :models
Model.rb:
belongs_to Manufacturer
has_many :tints
You need to first join the three models together, and then order by some criteria
tints_controller.rb
#tints = Tint.joins(model: :manufacturer).order('manufacturers.name, models.name').pluck('manufacturers.name, models.name, tints.front, tints.side, tints.rear')
That will give you all tints records and they appropiate models and manufacturers.
Any time you have the id of an entity in Rails, you can easily retrieve other associated fields simply by instantiating that entity:
#manufacturer = Manufacturer.find(params[manufacturer_id])
Then it's a simple matter to retrieve any of the other fields:
#manufacturer_name = #manufacturer.name
If you need a collection of manufacturers or manufacturer names, then it's advisable to build yourself an ActiveRecord::Relation object immediately via a scoped query (as you already know). I have no idea what your criteria are, otherwise, I'd supply some sample code. I can tell you that your scoped query should include an .order clause at the end:
#manufacturers = Manufacturer.where("some_column = ?", some_criterion).order(:sort_field)
In the above example, :sort_field would be the field by you want to sort your ActiveRecord::Relation. I'm guessing in your case, it's :name.
All this having been said, if you want fancy sorted tables, you should look into the JQuery DataTables gem. DataTables can do a lot of the heavy lifting for you, and it's convenient for your users because they can then sort and resort by any column you present.
In your tints_controller.rb, instedad of
#tints = Tint.all.order(:manufacturer_id)
please write:
#tints = Tint.all.order(:manufacturer_id, :model_id)
Answer to my question:
In tints_controller.rb, I wrote
#tints = Tint.joins(:manufacturer, :model).order("manufacturers.name ASC, models.name ASC") to join the table and order them accordingly.
I tried the answer provided by #Goston above and I had an issue when I was trying edit the tints. It did not allow me to edit.
Note: Answer provided by #Goston will order them, but it broke the edit function for my case.
I've got a table like this:
table: searches
+------------------------------+
| id | address | date |
+------------------------------+
| 1 | 123 foo st | 03/01/13 |
| 2 | 123 foo st | 03/02/13 |
| 3 | 456 foo st | 03/02/13 |
| 4 | 567 foo st | 03/01/13 |
| 5 | 456 foo st | 03/01/13 |
| 6 | 567 foo st | 03/01/13 |
+------------------------------+
And want a result set like this:
+------------------------------+
| id | address | date |
+------------------------------+
| 2 | 123 foo st | 03/02/13 |
| 3 | 456 foo st | 03/02/13 |
| 4 | 567 foo st | 03/01/13 |
+------------------------------+
But ActiveRecord seems unable to achieve this result. Here's what I'm trying:
Model has a 'most_recent' scope: scope :most_recent, order('date_searched DESC')
Model.most_recent.uniq returns the full set (SELECT DISTINCT "searches".* FROM "searches" ORDER BY date DESC) -- obviously the query is not going to do what I want, but neither is selecting only one column. I need all columns, but only rows where the address is unique in the result set.
I could do something like Model.select('distinct(address), date, id'), but that feels...wrong.
You could do a
select max(id), address, max(date) as latest
from searches
group by address
order by latest desc
According to sqlfiddle that does exactly what I think you want.
It's not quite the same as your requirement output, which doesn't seem to care about which ID is returned. Still, the query needs to specify something, which is here done by the "max" aggregate function.
I don't think you'll have any luck with ActiveRecord's autogenerated query methods for this case. So just add your own query method using that SQL to your model class. It's completely standard SQL that'll also run on basically any other RDBMS.
Edit: One big weakness of the query is that it doesn't necessarily return actual records. If the highest ID for a given address doesn't corellate with the highest date for that address, the resulting "record" will be different from the one actually stored in the DB. Depending on the use case that might matter or not. For Mysql simply changing max(id) to id would fix that problem, but IIRC Oracle has a problem with that.
To show unique addresses:
Searches.group(:address)
Then you can select columns if you want:
Searches.group(:address).select('id,date')
I use EntityFramework and need assistance with LINQ query.
Im building an application that will store articles.
Same article can be translated to many languages.
So I have 2 tables:
Article table:
ArticleId
ResourceTitleId (FK: LocalizedContent.ResourceId)
ResourceContentId (FK: LocalizedContent.ResourceId)
LocalizedContent table:
ResourceId
LanguageId
Content
So, for sake of example, if I have article in English and Russian,
I would store one row in Article table which would look like that:
ArticleId | ResourceTitleId | ResourceContentId |
-----------|-----------------|-------------------|
1| 1 | 2 |
And then, LocalizedContent table will look like this:
ResourceId | LanguageId | Content |
------------|------------|---------|
1| 1 | aaa |
------------|------------|---------|
1| 2 | zzz |
------------|------------|---------|
2| 1 | bbb |
------------|------------|---------|
2| 2 | yyy |
And now for the question:
I want to select an article by language id (lets say English), and I want my result to look like that:
ArticleId | ResourceTitle | ResourceContent |
-----------|---------------|-----------------|
1| aaa | bbb |
How do I perform LINQ query that will retrieve me that result in one query?
Just perform an inner join between the two tables filtering them by LanguageId.
var english = 1;
var query =
from article in dc.Articles
join resourceTitle in dc.LocalizedContent
on article.ResourceTitleId equals resourceTitle.ResourceId
join resourceContent in dc.LocalizedContent
on article.ResourceContentId equals resourceContent.ResourceId
where resourceTitle.LanguageId == english
&& resourceContent.LanguageId == english
select new
{
article.ArticleId,
ResourceTitle = resourceTitle.Content,
ResourceContent = resourceContent.Content,
};