Shorten the table names - sql

I am using SQL Server and wondering if it's possible to shorten the table names. For example, my current SQL syntax is:
SELECT
t.Titlename
FROM [dbo].[Order] o
JOIN [dbo].[Title] t ON o.titleid=t.TitleId
However, if I just try doing select titlename from order I get an error. Why is this so? What would be the 'shortest' tablename I could reference; and why is it requiring the [dbo] namespace?

It doesn't require the [dbo] namespace, assuming that is the currently selected database. But it does require the Title table to be joined to Order to get the Titlename column:
SELECT
t.Titlename
FROM [Order] o
JOIN Title t ON o.titleid=t.TitleId
Demo on SQLFiddle
Note that Order must be enclosed in [] because it is an SQL reserved keyword.
It's also worth noting the point that is made in the article #GregLow mentions, which indicates that queries cannot be reused if object name resolution needs to occur. So it would generally be preferred to write the query as you originally did.

If your currently selected database be dbo, then it shouldn't be necessary to use the fully qualified object name. However, you have another problem, because ORDER is a reserved SQL Server keyword. The following should work:
SELECT t.Titlename
FROM [Order] o
INNER JOIN [Title] t
ON o.titleid = t.TitleId;
Here, using [Order] instead of Order counts as escaping that table name.

Related

Using a function in a select statement with multiple tables while creating a view

I'm using oracle SQL developer, the create view tool. I have a function called LastNameFirst that I want to use to reorganize the customers first name / last name to appear with the last name being first.
SELECT SALE.SaleID,SALE.SaleDate, CUSTOMER.LastNameFirst(LastName,FirstName),
SALE_ITEM.SaleItemID,SALE_ITEM.ItemID,ITEM.ItemDescription, ITEM.ItemPrice
FROM SALE_ITEM
INNER JOIN SALE on SALE.SaleID = SALE_ITEM.SaleID
INNER JOIN ITEM on ITEM.ItemID = SALE_ITEM.ItemID
INNER JOIN CUSTOMER on CUSTOMER.CustomerID = SALE.CUSTOMERID;
The error i'm getting is :
ORA-00904: "CUSTOMER"."LASTNAMEFIRST": invalid identifier
How do I call the function in that part of my select statement? I can't seem to find any examples of functions being called in select statements where joins are involved, other than using "cross apply" or "outer apply" in some way. I understand (I think) that the syntax is
SELECT 'tableName'.'columnName'
and I know my function isn't a column and that's why I'm getting that error. But I'm really not sure of how to set up the code. I tried changing it to something like:
SELECT SALE.SaleID,SALE.SaleDate,CUSTOMER.LastName, CUSTOMER.FirstName AS LastNameFirst(LastName,FirstName),SALE_ITEM.SaleItemID,SALE_ITEM.ItemID,ITEM.ItemDescription, ITEM.ItemPrice
But nothing like that worked for me either. I'd appreciate any help anyone could give me.
Functions are not properties of tables to be allowed to period qualify them. However, functions and tables among other objects share the same namespace. As mentioned in docs:
The following schema objects share one namespace:
Tables
Views
Sequences
Private synonyms
Stand-alone procedures
Stand-alone stored functions
Packages
Materialized views
User-defined types
Therefore, simply remove the CUSTOMER. qualifier as schema is implicitly defined:
SELECT SALE.SaleID,
SALE.SaleDate,
LastNameFirst(LastName, FirstName) AS Customer_Name, ...
Alternatively, explicitly qualify the schema name on all table and function objects in the manner: "schema"."table"."column" or "schema"."function":
SELECT myschema.SALE.SaleID,
myschema.SALE.SaleDate,
myschema.LastNameFirst(myschema.CUSTOMER.LastName,
myschema.CUSTOMER.FirstName) AS Customer_Name, ...

SQL Server Object Names

I am wondering if someone can explain the concept of uniquely identifying sql server objects in a join.
In my example there are 2 schemas and 2 tables (but with same name). My assumption was that even though table name might be same between 2 schemas, as long as they are referenced with their full qualified name databasename.schemaname.objectname, SQL server should be able to make out the difference. However that does not seem to be the case and the workaround for this is to use alias.
I would appreciate If someone can explain or point out to some literature around why sql server cannot uniquely identity these.
CREATE SCHEMA [Sch1]
GO
CREATE SCHEMA [Sch2]
GO
CREATE TABLE [Sch1].[Table_1](
[ID] [int] NULL,
[DESC] [nchar](10) NULL
) ON [PRIMARY]
GO
CREATE TABLE [Sch2].[Table_1](
[ID] [int] NULL,
[DESC] [nchar](10) NULL
) ON [PRIMARY]
GO
Select *
From Sch1.Table_1
Join Sch2.Table_1
on Sch1.Table_1.Id = Sch2.Table_1.Id
The SQL Server supports muliti-part identifiers:
linked_server.db_name.schema.table_name
In your case you have:
Select *
From Sch1.Table_1
Join Sch2.Table_1
on Sch1.Table_1.Id = Sch2.Table_1.Id
Now you wonder why SQL Server cannot differentiate between them:
Sch1.Table_1 != Sch2.Table_1
The case is because of SQL Server use something called exposed name.
exposed name
which is the last part of the multi-part table name (if there is no
alias), or alias name when present
Returning to your query you have exposed names Table_1 and Table_1 which are duplicates and you need to use aliases.
From SQL Server 2005+:
Duplicate table detection algorithm has been changed correspondingly,
so that any tables with the same exposed names will be considered
duplicates
I suspect that your code could work with SQL Server 2000 but I cannot check it for sure.
For more info read Msg 1013
As far as I can tell, I don't see any errors in your sample code. Please explain in detail what errors you're encountering.
As for the four-part naming convention. the full object name syntax is:
server.database.schema.object
So a complete usage would be, for example:
select * from servername.databasename.Sch1.Table_1
or
select * from servername.databasename.Sch2.Table_2
from which you can ignore any part as long as there is no ambiguity. Therefore in your example you can ignore severname and databasename as they are the same. But you cannot ignore schema names as they are not.
Addendum:
Based on error message you posted later, you need to employ correlation naming on the join syntax:
select *
from Sch1.Table_1 as t1
inner join Sch2.Table_1 as t2 on t1.ID=t2.ID
Select *
From Sch1.Table_1 x
Join Sch2.Table_1 y
on x.Id = y.Id
Does this work?

The multi-part identifier "tablename.column " could not be bound

When I used this query above exception has thrown
SELECT FINQDET.InquiryNo,FINQDET.Stockcode,FINQDET.BomQty,FINQDET.Quantity,FINQDET.Rate,FINQDET.Required,FINQDET.DeliverTo,FSTCODE.TitleA AS FSTCODE_TitleA ,FSTCODE.TitleB AS FSTCODE_TitleB,FSTCODE.Size AS FSTCODE_Size,FSTCODE.Unit AS FSTCODE_Unit, FINQSUM.TITLE AS FINQSUM_TITLE,FINQSUM.DATED AS FINQSUM_DATED
FROM FINQSUM , FINQDET left outer join [Config]..FSTCODE ON FINQDET.Stockcode=FSTCODE.Stockcode
WHERE FINQDET.InquiryNo=FINQSUM.INQUIRYNO
ORDER BY FINQDET.Stockcode,FINQDET.InquiryNo
but if I used below query problem solved,
SELECT FINQDET.InquiryNo,FINQDET.Stockcode,FINQDET.BomQty,FINQDET.Quantity,FINQDET.Rate,FINQDET.Required,FINQDET.DeliverTo,FSTCODE.TitleA AS FSTCODE_TitleA ,FSTCODE.TitleB AS FSTCODE_TitleB,FSTCODE.Size AS FSTCODE_Size,FSTCODE.Unit AS FSTCODE_Unit,
FINQSUM.TITLE AS FINQSUM_TITLE,FINQSUM.DATED AS FINQSUM_DATED
FROM FINQSUM As FINQSUM , FINQDET As FINQDET left outer join [Config]..FSTCODE As FSTCODE ON FINQDET.Stockcode=FSTCODE.Stockcode
HERE FINQDET.InquiryNo=FINQSUM.INQUIRYNO
ORDER BY FINQDET.Stockcode,FINQDET.InquiryNo
Please can you explain Why using Alias better than using actual table names
The table [Config]..FSTCODE is qualified with database name which works fine if you use alias. Otherwise you need to qualify full name as it is from different database
Looks like FSTCODE is a table in a different DB. In the first query, though the JOIN uses the DB name to identify the table, the ON statement does not. The second statement adresses this by using an ALIAS
You can also modify the first statement as
left outer join [Config]..FSTCODE
ON FINQDET.Stockcode=[Config]..FSTCODE.Stockcode
An alias allows you to reference a set without using the fullname. It saves you typing and allows you to express contextual information to the reader.

ORDER BY items must appear... but I have no ORDER BY clause

I am getting the well-documented error:
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
Here's my SQL statement:
INSERT INTO PropertyList
(PropertyID, Initials)
SELECT DISTINCT P.PropertyID, "vSTEBCodes"
FROM Property AS P INNER JOIN ValiditySTEBCodes AS VC
ON P.ControlNumber=VC.ControlNumber
As you can see there is no ORDER BY statement in sight. Presumably there is an implied ORDER BY in there somewhere, but I can't see it.
I am running this statement against linked tables in MS Access that are linked to a SQL Server 2008 back-end. When I run it from a full version of Access 2002, it runs without issue. If I try to run it from an Access 2000 runtime I receive the error shown.
I know that Access has a tendency to re-write queries in the background before forwarding them to ODBC sources (especially multi-record INSERTs and UPDATEs). I'm thinking that may be the issue.
Compiling from the comments, try:
INSERT INTO dbo.PropertyList(PropertyID, Initials)
SELECT P.PropertyID, Initials = 'vSTEBCodes' -- alias and single quotes
FROM dbo.Property AS P -- always use schema prefix
INNER JOIN dbo.ValiditySTEBCodes AS VC
ON P.ControlNumber = VC.ControlNumber
GROUP BY P.PropertyID -- instead of DISTINCT
ORDER BY P.PropertyID; -- maybe overrides Access stupidity

SQL Server distinct not being used properly

I'm trying to select just one account using SQL Server but am getting the following error:
ERROR: The text data type cannot be selected as DISTINCT because
it is not comparable. Error Code: 421
with the following statement:
select DISTINCT ad.*,
acc.companyname,
acc.accountnumber
from address ad
join AddressLink al on al.AddressID = ad.id
join account acc on acc.ID = al.ParentID
where acc.accountnumber like '11227'
What have I done wrong?
Edit:
New query:
select address.ID,
address.StreetAddress1,
address.StreetAddress2,
address.City,
Address.State,
Address.PostalCode,
Address.ClassTypeID,
account.companyname,
account.accountnumber,
addresslink.ID as addressLinkID,
addresslink.addresstypeid
from address
join AddressLink on address.id = addresslink.AddressID
join account on addresslink.ParentID = account.ID
where account.CompanyName like 'company name'
All the company names that I've had to blur are identical.
Try:
select ad.*,
l.companyname,
l.accountnumber
from address ad
join (select DISTINCT al.AddressID,
acc.companyname,
acc.accountnumber
from account acc
join AddressLink al on acc.ID = al.ParentID
where acc.accountnumber like '11227') l
on l.AddressID = ad.id
"Distinct", in the context you have is trying to do distinct on ALL columns. That said, there are some data types that are NOT converable, such as TEXT. So, if your table has some of these non "Distinctable" column types exists, that is what is crashing your query.
However, to get around this, if you do something like
CONVERT( char(60), YourTextColumn ) as YourTextColumn,
It should get that for you... at least its now thinking the final column type is "char"acter and CAN compare it.
You should check the data types of the columns in the address table. My guess is that one or more of them has the data type text, ntext or image.
One of the restrictions of using text, ntext or image data types is that columns defined of these data types cannot be used as part of a SELECT statement that includes the DISTINCT clause.
For what it's worth, the MSDN article for ntext, text, and image (Transact-SQL) recommends avoiding these data types and use nvarchar(max), varchar(max), and varbinary(max) instead. You may want to consider changing how that table is defined.
The accepted answer from Mark B shows a subquery (good idea to limit the domain of the DISTINCT) on AddressLink.AddressId, Account.CompanyName, and Account.AccountNumber.
Let me ask this: Does AddressLink allow more than one record to have the same value in the ParentId and AddressId fields?
If not, and assuming that Mark B's answer works, then just remove the DISTINCT because you're never going to get any duplicates inside of that subquery.
Leaving the DISTINCT in causes a performance hit because the DB has to create a temporary table that is either indexed with a btree or a hash and it has to insert every value returned by the subquery into that table to check if it invalidates the uniqueness constraint on those three fields. Note that the "optimizer" doesn't know that there won't be any dupes... if you tell it to check for DISTINCT, it will check it... With a btree index this is going to cause O(n log n) work on the number of rows returned; with a hash it would cause O(n) work but who knows how big the constant factor is in relation to the other work you're doing (it's probably larger than everything else you're doing meaning this could make this run half as fast as without the DISTINCT).
So my answer is Mark B's answer without the DISTINCT in the subquery. Let me know if AddressLink does allow repeats (can't imagine why it would).