When to use three-part column references in SQL 2014 - sql

Firstly, apologies if this is in the wrong section, or the wrong style. Hunted for this answer for a while, to no avail.
Imagine you have a (sample) SQL query in SQL 2014 -
SELECT
dbo.Users.Surname,
dbo.Accounts.Type
FROM
dbo.Users
INNER JOIN
dbo.Accounts
ON (dbo.Users.Id = dbo.Accounts.Id)
Up until now, this is the format I've been using - fully qualifying the table objects with [schema].[tablename].[column].
However, looking at the SQL 2014 Deprecated Database Engine Features, it says that this style is no longer standard -
Two-part names is the standard-compliant behavior.
After digging around for a while, I found the Transact-SQL Syntax Conventions, where it says -
To avoid name resolution errors, we recommend specifying the schema name whenever you specify a schema-scoped object.
So I'm a little confused as to how my little code snippet should be written. Should I only use the schema when referencing the tables, but when referring to columns, skip the schema and just use the table names? Or is it assuming all table objects should have an alias?
Again, apologies for the potential subjectivity of this question. But essentially I'm asking about how to write SQL that does not use a deprecated feature of SQL 2014, but still reads well when joining multiple tables.

It says that the deprecated feature applies to referencing columns, not tables.
To clarify imagine two statements:
SELECT dbo.Orders.ID FROM dbo.Orders
and
SELECT Orders.ID FROM dbo.Orders
The first is deprecated, not the last.
To avoid name resolution errors, we recommend specifying the schema
name whenever you specify a schema-scoped object.
This applies to default schema of user. If user has default schema say 'Person' and two tables with the same name 'dbo.Persons', 'Person.Persons' exist in the database, then if that user executes:
SELECT * FROM Persons
he will get results from table in Person schema, even if he did want data from dbo.
So the actual answer is:
Use
SELECT Orders.ID FROM dbo.Orders

Related

Can I use an IN clause with a LEFT JOIN clause

FORE NOTE: This question regards the IN clause that belongs in the FROM statement and lets you reference to an external database. Do not confuse this with the IN statements that might live in a WHERE clause, please.
Version: MS Access 2016
External table is on the local network
The crux of what I am trying to do is grab an [Employee] table from an external ACCDB database and LEFT JOIN it to a local [Employees] (note the 's') table. I am trying to generate a list of (non-terminated) employees that are not yet added to my local [Employees] table. As in:
SELECT Employee.Last_Name, Employee.First_Name, Employee.Job_Title
FROM Employee IN "\\{full path}\Time Clock 1.0_be.accdb"
LEFT JOIN Employees
ON Employee.Last_Name = Employees.LastName
AND Employee.First_Name = Employees.FirstName
WHERE Employees.FirstName IS NULL
AND Employee.Termination_Date = ""
ORDER BY Employee.Last_Name, Employee.First_Name;
Only the above SQL doesn't work. Access gives me the ever-so-not-very helpful Syntax error in FROM clause to brighten my neurotic insanity.
Does the IN clause have to go last and does it effect both tables? At:
https://msdn.microsoft.com/en-us/library/bb177907(v=office.12).aspx
they say it can be combined with a LEFT JOIN but they don't specify if both tables must be external.
Can you even LEFT JOIN a table from an external DB to an local table? I don't really want to link the table formally as this query will only run occasionally and I don't want any more traffic pinging the Time Clock back end DB than I have to. It's slow enough as it is.
In answer to my original question:
#cha was right to suggest I use nested queries. This solves the problem of an internal table being joined to an external table.
#Gord Thompson had a much more specific way of referencing to an external DB that seems clearer to me than the IN clause in this simple case. Programmers may want to use the IN clause when connecting to different types of external databases as it gives you the ability to specify all that in the IN clause.
In the end none of this helped me because the train-wreck-of-a-database I lovingly caress uses multi-value fields and Access will not link an internal table with multi-valued fields to an external table.
Those who come after you (and probably you yourself) will thank you for observing 1st 2nd and 3rd normal forms except in the most unusual and carefully considered cases and for never ever ever ever using multi-valued fields instead of linking tables for many-to-many relationships.
Aloha!

How to join a table within a user defined function whose name is provided as parameter?

Context
I have three tables in my SQL Server database: 1) School, 2) College, 3) University.
Then I have another table: Tags.
Each of the three tables (School, College, University) can have Tags associated with them. For which purpose I have three association tables: SchoolTags, CollegeTags, UniversityTags.
Problem
I am trying to create a user-defined function that will take the name of association table as parameter (i.e. 'SchoolTags') and the Id of the entity (school/college/university) and will return a list of tags associated with that entityId.
The issue I am having is I have got to join Tags with a table whose name will come in as parameter. For that I am creating a dynamic query. And we can not run dynamic queries in SQL Server user-defined functions.
Question
Any idea how can that be acheived?
Note: I want separate association tables as I have created and do not want to convert them into a generic association table and I do not want to add If-Else based on table names in my function so that if a new association table is created, I do not need to update my function.
I am using Microsoft SQL Server.
Whatever language you are using, you would probably use if:
begin
if table = 'school' then
begin
. . .
end;
else if table = 'college' then
. . .
end;
The exact syntax depends on the scripting language for the database you are using.
What you desire is impossible. You cannot pass a table name as a parameter to a UDF and use dynamic sql in the UDF to then create and execute a statement that is specific to the table passed as the argument. You already know that you have no choice but to use if-else statements in your UDF to achieve your goal - it is your pipe-dream of "never having to update (or verify) your code when the schema changes" (yes - I rephrased it to make your issue more obvious) that is a problem.
There are likely to be other ways of implementing some useful functionality - but I suggest that you are thinking too far ahead and trying to implement generic functions without a clear purpose. And that is a very difficult and trouble-prone path that requires sophisticated tsql skills.
And to re-iterate the prior responses, you have a schema problem. You purposely created three different entities - and now you want a common function to use with any of them. So before you spend much time on this particular aspect, you should take some time to think carefully about how you intend to use (i.e., write queries against) these tables. If you find yourself using unions frequently to combine these entities into a common resultset, then you have might have a mismatch between your actual business and your model (schema) of it.
Consider normalizing your database in related, logical groupings for one EducationInstitution table and one JoinEducTags table. Those tables sound like they maintain the same structure but of different typology and hence should be saved in one table with different Type field for School, College, University, etc.
Then, add necessary constraints, primary/foreign keys for the one-to-many relationship between all three sets:
You never want to keep restructuring your schema (i.e., add tables) for each new type. With this approach, your user-defined function would just need to receive value parameters not identifiers like tables to be run in dynamic querying. Finally, this approach scales better with efficient storage. And as you will see normalization saves on complex querying.

Join query referencing table name causes problems?

I have a sql query (used with MS Access and C#) that in the where clause references table name with the column, that causes an error. When I remove the table name, it works fine, but it would seem like if you are more specific, it would work better?
Anyone have any ideas why that is?
SQL query in question:
SELECT profiles.profile_id,
profiles.full_name,
shifts.start,
shifts.stop,
shifts.start_log,
shifts.stop_log,
shifts.start_notes,
shifts.stop_notes
FROM shifts,
profiles
WHERE profile.full_name=#full_name AND
shifts.profile_id=profiles.profile_id;
I had to change "profile.full_name=#full_name" in the WHERE clause to "full_name=#full_name" i.e. remove the table name "profile".
This question came from another SO question found here
Your query pulls information from a table named profiles, so profile.full_name is not defined because there is no table (or alias) named profile in the query. profiles.full_name would probably work better.

Is there any use to duplicate column names in a table?

In sqlite3, I can force two columns to alias to the same name, as in the following query:
SELECT field_one AS overloaded_name,
field_two AS overloaded_name
FROM my_table;
It returns the following:
overloaded_name overloaded_name
--------------- ---------------
1 2
3 4
... ...
... and so on.
However, if I create a named table using the same syntax, it appends one of the aliases with a :1:
sqlite> CREATE TABLE temp AS
SELECT field_one AS overloaded_name,
field_two AS overloaded_name
FROM my_table;
sqlite> .schema temp
CREATE TABLE temp(
overloaded_name TEXT,
"overloaded_name:1" TEXT
);
I ran the original query just to see if this was possible, and I was surprised that it was allowed. Is there any good reason to do this? Assuming there isn't, why is this allowed at all?
EDIT:
I should clarify: the question is twofold: why is the table creation allowed to succeed, and (more importantly) why is the original select allowed in the first place?
Also, see my clarification above with respect to table creation.
I can force two columns to alias to the same name...
why is [this] allowed in the first place?
This can be attributed to the shackles of compatibility. In the SQL Standards, nothing is ever deprecated. An early version of the Standard allowed the result of a table expression to include columns with duplicate names, probably because an influential vendor had allowed it, possibly due to the inclusion of a bug or the omission of a design feature, and weren't prepared to take the risk of breaking their customers' code (the shackles of compatibility again).
Is there any use to duplicate column names in a table?
In the relational model, every attribute of every relation has a name that is unique within the relevant relation. Just because SQL allows duplicate column names that doesn't mean that as a SQL coder you should utilise such as feature; in fact I'd say you have to vigilant not to invoke this feature in error. I can't think of any good reason to have duplicate column names in a table but I can think of many obvious bad ones. Such a table would not be a relation and that can't be a good thing!
why is the [base] table creation allowed to succeed
Undoubtedly an 'extension' to (a.k.a purposeful violation of) the SQL Standards, I suppose it could be perceived as a reasonable feature: if I attempt to create columns with duplicate names the system automatically disambigutes them by suffixing an ordinal number. In fact, the SQL Standard specifies that there be an implementation dependent way to ensure the result of a table expression does not implicitly have duplicate column names (but as you point out in the question this does not perclude the user from explicitly using duplicate AS clauses). However, I personally think the Standard behaviour of disallowing the duplicate name and raising an error is the correct one. Aside from the above reasons (i.e. that duplicate columns in the same table are of no good use), a SQL script that creates an object without knowing if the system has honoured that name will be error prone.
The table itself can't have duplicate column names because inserting and updating would be messed up. Which column gets the data?
During selects the "duplicates" are just column labels so do not hurt anything.
I assume you're talking about the CREATE TABLE ... AS SELECT command. This looks like an SQL extension to me.
Standard SQL does not allow you to use the same column name for different columns, and SQLite appears to be allowing that in its extension, but working around it. While a simple, naked select statement simply uses as to set the column name, create table ... as select uses it to create a brand new table with those column names.
As an aside, it would be interesting to see what the naked select does when you try to use the duplicated column, such as in an order by clause.
If you were allowed to have multiple columns with the same name, it would be a little difficult for the execution engine to figure out what you meant with:
select overloaded_name from table;
The reason why you can do it in the select is to allow things like:
select id, surname as name from users where surname is not null
union all
select id, firstname as name from users where surname is null
so that you end up with a single name column.
As to whether there's a good reason, SQLite is probably assuming you know what you're doing when you specify the same column name for two different columns. Its essence seems to be to allow a great deal of latitude to the user (as evidenced by the fact that the columns are dynamically typed, for example).
The alternative would be to simply refuse your request, which is what I'd prefer, but the developers of SQLite are probably more liberal (or less anal-retentive) than I :-)

SQL, How to change column in SQL table without breaking other dependencies?

I'm sure this might be quite common query but couldn't find good answer as for now.
Here is my question:
I've got a table named Contacts with varchar column Title. Now in the middle of development I want to replace field Title with TitleID which is foreign key to ContactTitles table. At the moment table Contacts has over 60 dependencies (other tables, views functions).
How can I do that the safest and easiest way?
We use: MSSQL 2005, data has already been migrated, just want to change schema.
Edit:
Thanks to All for quick replay.
Like it was mentioned Contacts table has over 60 dependents, but when following query was run, only 5 of them use Title column. Migration script was run, so no data changes required.
/*gets all objects which use specified column */
SELECT Name
FROM syscomments sc
JOIN sysobjects so ON sc.id = so.id
WHERE TEXT LIKE '%Title%' AND TEXT LIKE '%TitleID%'
Then I went through those 5 views and updated them manually.
Use refactoring methods. Start off by creating a new field called TitleID, then copy all the titles into the ContactTitles table. Then, one by one, update each of the dependencies to use the TitleID field. Just make sure you've still got a working system after each step.
If the data is going to be changing, you'll have to be careful and make sure that any changes to the Title column also change the ContactTitles table. You'll only have to keep them in sync while you're doing the refactoring.
Edit: There's even a book about it! Refactoring Databases.
As others pointed out it depends on your RDBMS.
There are two approaches:
make a change to the table and fix all dependencies
make a view that you can use instead of direct access to the table (this can guard you against future changes in the underlying core table(s), but you might loose some update functionality, depending on your DBMS)
For Microsoft SQL Server Redgate have a (not free) product that can help with this refactoring http://www.red-gate.com/products/sql_refactor/index.htm
In the past I have managed to do this quite easily (if primitively) by simply getting a list of things to review
SELECT * FROM sys.objects
WHERE OBJECT_DEFINITION(OBJECT_ID) LIKE '%Contacts%'
(and possibly taking dependencies information into account and filtering by object type)
Scripting all the ones of interest in Management Studio then simply going down the list and reviewing them all and changing the CREATE to ALTER. It should be quite a simple and repetitive change even for 60 possible dependencies. Additionally if you are referring to a non existent column you should get an error message when you run the script to ALTER.
If you use * in your queries or adhoc SQL in your applications obviously things may be a bit more difficult.
Use SP_Depend 'Table Name' to check the Dependencies of the table
and then Use the SP_Rename to Rename the Column Name which is very useful.
sp_rename automatically renames the associated index whenever a PRIMARY KEY or UNIQUE constraint is renamed. If a renamed index is tied to a PRIMARY KEY constraint, the PRIMARY KEY constraint is also automatically renamed by sp_rename.
and then start Updating the Procedure and Functions one by one there is no other good option for change like this if you found then tell me too.