Automatic Normalization of VARCHAR columns? - sql

Imagine you have many tables which have a VARCHAR(50) column called Country, there is a small number of different country names which repeat millions of times, the wise thing to do here is to create a table called dbo.Country(CountryID, CountryName) and have all the tables hold CountryID with a foreign key reference.
Problem is we have to JOIN all our queries with dbo.Country every time we want do something with that column.
But all the joins seem to follow the same pattern, so my question is, can SQL Server do it automatically? For example I would specify a column called CountryName in some table which looks like a VARCHAR but is actually stored as a CountryID with foreign key, and SQL Server could implicitly add the JOIN whenever necessary.
Is there such a feature in SQL Server or any other SQL database?

You can't do this "automatically". However, you do have a couple of options.
One is to create a view on top of the table that automatically does the join:
create view v_table as
select t.*, c.CountryName
from table t join
country c
on t.countryId = c.countryId;
Alternatively, you could make Country an enumerated type. That would allow it to be accessed as a string but stored as an integer.

Related

Set column value to foreign key based on another column

I am using SQL Server and have imported data from an Excel file into my tables.
My tables consist of:
BH_Overview (foreign key table) BH_OverView Table
BH_Equipment (primary key table) BH_Equipment Table
I have different types of equipment and looking to split it out into its own table called BH_Equipment and link it into the main table BH_Overview.
I have my tables created and constraints made, however when data is imported into table I have just stored the equipment name in the the BH_Overview table in a column "Equipment" that isn't link with BH_Equipment.
I'm wondering how I go about updating the equipmentId column based on what is in the equipment column in the BH_Overview table to match the Id in the BH_Equipment table.
You can see I have the foreign keys done for Factory Area and responsibility and that was done manually with update statement as only a few foreign keys to link but with equipment there is 291 types in the BH_Equipment table.
I have tried a update and inner joins, but can't get my head around it. Apologies if I have went about this an awful way, relatively new to SQL so please show if there is a much easier way or if this has been asked before please link and ill give it a look.
UPDATE:
#Charlieface - error message appearing
The other answer is good, but for SQL Server you can update much more easily directly through a join:
update o
set equipmentId = e.id
from BH_OverView o
join BH_Equipment e on e.equipment = o.Equipment;
This rough syntax also works on Postgres, MySQL/MariaDB and the later versions of SQLite.
First, you should have the content of the column Equipment in the table BH_OverView match one of column equipment content in the table BH_Equipment
Then by the following SQL statement, you populate the corresponding equipmentId in the table BH_OverView
update BH_OverView
set equipmentId = (select id from BH_Equipment
where BH_Equipment.equipment=BH_OverView.Equipment)
after verifying the content of equipmentId in the table BH_OverView, you may drop the column Equipment from the table BH_OverView by
alter table BH_OverView drop column Equipment
I am using standard SQL which should operate on the majority of Databases.
Based on your comment
you got an error message
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
This means that in your table BH_Equipment, you have one more equipment that has the same name. You have repeated equipment name in rows of the table BH_Equipment
to get this equipment and the number of time they exist, use the following SQL statement
select equipment, count(id)
from BH_Equipment
group by equipment
having count(id)>1
delete one of the repeated rows, then the error message will not exist.

Tables not showing anything when creating new one

I have problem with SQL .
I am trying to create tables from other tables with foreign keys. The table is created normally without problem but when I'm trying to see the data inside the table there is none of the data inside! Anyone who knows?
-- Here is my table with the foreign keys
CREATE TABLE StaffXCustomersXMeals(
--MealID int FOREIGN KEY REFERENCES Meals(MealID),
--CustomersID int FOREIGN KEY REFERENCES Customers(CustomersID),
--StaffID int FOREIGN KEY REFERENCES Staff(StaffID)
)
You might want to consider reading up on the concept of a SQL View - think of it as a "virtual table based on the result-set of an SQL statement." When you create a view based on the JOIN between multiple tables, it saves your query and you can then select from it like you would a table.
For example, you might have the following:
CREATE VIEW StaffCustomerMeals
AS
SELECT
m.MealID,
c.CustomersID,
s.StaffID
FROM
Meals m
LEFT JOIN
Customers c ON
m.SomeIDThatMeansThisCustomer = c.CustomersID
LEFT JOIN
Staff s ON
m.SomeIDThatMeansAStaffMember = s.StaffID
You need to define these relationships in accordance with your own schema - it's your homework assignment, so do your best to figure it out. A couple more questions to consider:
Does a meal always have both a customer and a staff member, or are they customers who might happen to be staff members?
Should you include other information besides the IDs (e.g., CustomerName, StaffMemberDepartment, MealPrice, PurchaseDate)
You didn't enter any data. You only said that whatever data entered must reference the other tables. So you cannot enter invalid meals for instance.
You need INSERT statments to fill the table with whatever data you need.

Combining amendsments to database table fields

I am interested to understand the correct approach to solving a database problem I find myself faced with.
I have a table (with ~45 columns) that holds information about stock, it's pricing and a lot of information relating to it's packaging, discounting, etc.
The stock is accessed via a web application using ADO (VB6) by constructing TSQL queries in numerous places.
There is now a need to hold a new table with a very cut down list of the above columns to allow some users to override parts of the stock information from the source (mainly descriptions and such).
The problem I'm faced with is coming up with a way to (perhaps) construct a view of the two tables such that the software still thinks it is talking to the first table (changing the software is simply a no-go) when in fact it is the first table amended by the second, perhaps via some sort of UNION.
To present a simple example, suppose you have a stock table as:
CREATE TABLE Stock
(
id int NOT NULL,
ref varchar(20) NOT NULL,
short_description varchar(50) NOT NULL,
long_description varchar(255) NOT NULL,
...many other columns
)
and an amendments table as:
CREATE TABLE StockAmendments
(
id int NOT NULL,
ref varchar(20) NOT NULL,
short_description varchar(50) NOT NULL
)
The idea would be to rename Stock as StockSource and to build a view called Stock which amends StockSource with StockAmendments (in this case a potentially different short_description). This way the software does not need to know about the change.
Is this possible?
This should be doable. I haven't done t-sql in a very long time but something like this:
CREATE VIEW Stock
AS
SELECT
ss.id,
ss.ref,
iif(isnull(sa.short_description), ss.short_description, sa.short_description)) as short_description,
ss.long_description
FROM StockSource ss, StockAmendments sa
WHERE ss.id = sa.id AND ss.ref = sa.ref
One thing to worry about is query performance depending on indexes, etc. If this is a problem, you might be better off creating a real 'Stock' table based off of StockSource and putting a trigger on StockAmendments to update the 'Stock' table.
Yes it is possible using updatable views.
Rename Stock as StockSource and to build an updatable view Stock over StockSource and StockAmendments. This way you'll not have to do any change in VB6 code.

Complex queries in SQL Server 2005 database

I have a table in my database in which records conceptually can be children of other rcords. The table has a non-null name field. I need to ensure that each name in a set of children is unique, but not across the entire database. I'd like to enforce this using a constraint inside the Database. What's the best way to accomplish this?
I know that I am going to have to do a query at some point in the process like this:
#NameParameter NVARCHAR(512)
Select Name from MyTable
WHERE Name=#NameParameter
The question is where do I put this query?
I may not be understanding your question correctly, but my suggestion is to create another column that references the parent record of the child. You could then create a A multiple-column index based on those two columns to speed up any queries that reference these columns together in a where clause... Thus your uniqueness would come from {parent_name, child_name}. A constraint on these two columns would act as a key for that table, and not allow duplicates.
#childname NVARCHAR(255), #parentname NVARCHAR(255)
SELECT * FROM [child_records]
WHERE [parent_name] = #parentname
AND [child_name] = #childname
At first glance I believe this should go into a "Instead of trigger". This link provides a good example.

SQL statement from two tables

I would like to know if it is possible, to select certain columns from one table, and another column from a second table, which would relate to a non imported column in the first table. I have to obtain this data from access, and do not know if this is possible with Access, or SQL in general.
Assuming the following table structure:
CREATE TABLE tbl_1 (
pk_1 int,
field_1 varchar(25),
field_2 varchar(25)
);
CREATE TABLE tbl_2 (
pk_2 int,
fk_1 int,
field_3 varchar(25),
field_4 varchar(25)
);
You could use the following:
SELECT t1.field_1, t2.field_3
FROM tbl_1 t1
INNER JOIN tbl_2 t2 ON t1.pk_1 = t2.fk_1
WHERE t2.field_3 = "Some String"
In regard to Bill's post, there are two ways to create JOIN's within SQL queries:
Implicit - The join is created using
the WHERE clause of the query with multiple tables being specified in the FROM clause
Explicit - The join is created using
the appropriate type of JOIN clause
(INNER, LEFT, RIGHT, FULL)
It is always recommended that you use the explicit JOIN syntax as implicit joins can present problems once the query becomes more complex.
For example, if you later add an explicit join to a query that already uses an implicit join with multiple tables referenced in the FROM clause, the first table referenced in the FROM clause will not be visible to the explicitly joined table.
What you are looking for are JOINs:
http://en.wikipedia.org/wiki/Join_(SQL)
You need primary keys for the referenced data sets and foreign keys in the first table.
I'm not 100% sure I understand your question.
Is the following true:
Your first table is imported from somewhere else.
You are only importing some columns.
You want to build a query which references a column which you haven't imported.
If this is true, it's just not possible. As far as the Access query engine in concerned the non-imported columns don't exist.
Why not just import them as well?
But primary keys make the query more efficient