Second table name after FROM tables - sql

I'm editing some views and came across something that is new to me:
SELECT rn3.create_date
FROM receipt_note rn3
WHERE rn3.receipt_num = receipt_data.receipt_num
I'm just wondering what the rn3 does in the from part of the statement?
As there isn't a comma between them showing its another table and I dont see a table or view in my database called rn3.

It is called an Alias.
You can define another name to use in your queries. Mostly used as shorter name of tables to simplify your queries. Example:
select t.some_column
from very_long_table_name t
Or if you join the same table twice then you need aliases to distinguish between the two. Example:
select child.name, parent.name
from users child
join users parent on child.parent_id = parent.id
And as stated in comments: When using DB engines other than Oracle, you can but don't need to define the as keyword:
select t.*
from some_table_name as t

Related

Is this the table name?

I'm trying to learn SQL queries, and I've encountered things like this:
SELECT name FROM customer_list t
WHERE ...
What does the t mean? Is it like the name of an instance of that table?
Thanks!
The t is an alias that you can refer to instead of the table name in your query. If you have only one table you're querying from it isn't very useful, but it comes in hand when you have multiple tables (e.g., in join clauses and you want to avoid writing the entire long table name whenever you refer to it. E.g.:
SELECT t.name
FROM some_long_table_name t
JOIN some_other_long_table_name s ON t.id = s.id

Spooky query behavior : Same query, different results when inside a view

The same query brings different results when inside a View.
I tried to force same codepages, same data types, Common Query Expressions... none worked.
Have a look at this simple query:
SELECT TOP 100 CompanyID, SubsidiaryID
FROM STAGING.SALESAX S
INNER JOIN Subsidiary SU
ON S.CompanyID = SU.SubsidiaryAXCode
It returns all expected 100 rows.
If I use the EXACT SAME QUERY in a view:
CREATE VIEW [STAGING].[VSalesAXBASE]
AS
SELECT TOP 100 CompanyID, SubsidiaryID
FROM STAGING.SALESAX S
INNER JOIN Subsidiary SU
ON S.CompanyID = SU.SubsidiaryAXCode
GO
SELECT * FROM [STAGING].[VSalesAXBASE]
it returns 0 ROWS
You prefix SALESAX table with STAGING., but don't prefix Subsidiary table in the query. Do prefix all tables in the query.
One possibility is that there are several Subsidiary tables and the query uses different table in the context of the view.
By the way, it is also a good practice to prefix columns with table names in the SELECT part of the query. For example, right now it is hard to know from which table(s) the columns CompanyID and SubsidiaryID come from.
The solution was to add the DBO schemma to the subsidiary table.. thanks to the suggestions of #VladimirBaranov, #IMSoP and #Augustina(Codec)
Looks like the execution context of the view may be different from the current user (need to check more on this).
SQL does not guarantee the ordering of results unless an explicit Order By clause is used.

How to span mulitiple tables with a view, when the tables have same structure

So we have a db that receives constant input and then we have it moved after x days to a different db as a type of archive/reporting db. So the question is when I try to create a view that combines two of the tables (one from each db):
CREATE VIEW Table_Full AS
SELECT *
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME
I get the following error: "Column names in each view or function must be unique. Column name 'PARTNO' in view or function 'Table_Full' is specified more than once."
So, is there a better way to accomplish what I am trying to do or ?
Given your use case, I think you want a union. That is
select * from table_a
Union all
Select * from table_b
Instead of an asterisk, you have to specify each field and provide aliases for the duplicate field names:
CREATE VIEW Table_Full AS
SELECT
a.ID as A_ID,
b.ID as B_ID,
a.Thingy as A_Thingy,
a.Etcetera as Atcetera
FROM [Front].dbo.[DATA] AS A
Inner Join Back.dbo.DATA AS B
ON A.DATETIME=B.DATETIME

Reusing results from a SQL query in a following query in Sqlite

I am using a recursive with statement to select all child from a given parent in a table representing tree structured entries. This is in Sqlite (which now supports recursive with).
This allows me to select very quickly thousands of record in this tree whithout suffering the huge performance loss due to preparing thousands of select statements from the calling application.
WITH RECURSIVE q(Id) AS
(
SELECT Id FROM Entity
WHERE Parent=(?)
UNION ALL
SELECT m.Id FROM Entity AS m
JOIN Entity ON m.Id=q.Parent
)
SELECT Id FROM q;
Now, suppose I have related data to these entities in an arbitrary number of other tables, that I want to subsequently load. Due to the arbitrary number of them (in a modular fashion) it is not possible to include the data fetching directly in this one. They must follow it.
But, if for each related tables I then do a SELECT statement, all the performance gain from selecting all the data from the tree directly inside Sqlite is almost useless because I will still stall on thousands of subsequent requests which will each prepare and issue a select statement.
So two questions :
The better solution is to formulate a similar recursive statement for each of the related tables, that will recursively gather the entities from this tree again, and this time select their related data by joining it.
This sounds really more efficient, but it's really tricky to formulate such a statement and I'm a bit lost here.
Now the real mystery is, would there be an even more efficient solution, which would be to somehow keep these results from the last query cached somewhere (the rows with the ids from the entity tree) and join them to the related tables in the following statement without having to recursively iterate over it again ?
Here is a try at the first option, supposing I want to select a field Data from related table Component : is the second UNION ALL legal ?
WITH RECURSIVE q(Data) AS
(
SELECT Id FROM Entity
WHERE Parent=(?)
UNION ALL
SELECT m.Id FROM Entity AS m
JOIN Entity ON m.Id=q.Parent
UNION ALL
SELECT Data FROM Component AS c
JOIN Component ON c.Id=q.Id
)
SELECT Data FROM q;
The documentation says:
 2. The table named on the left-hand side of the AS keyword must appear exactly once in the FROM clause of the right-most SELECT statement of the compound select, and nowhere else.
So your second query is not legal.
However, the CTE behaves like a normal table/view, so you can just join it to the related table:
WITH RECURSIVE q(Id) AS
( ... )
SELECT q.Id, c.Data
FROM q JOIN Component AS c ON q.Id = c.Id
If you want to reuse the computed values in q for multiple queries, there's nothing you can do with CTEs, but you can store them in a temporary table:
CREATE TEMPORARY TABLE q_123 AS
WITH RECURSIVE q(Id) AS
( ... )
SELECT Id FROM q;
SELECT * FROM q_123 JOIN Component ...;
SELECT * FROM q_123 JOIN Whatever ...;
DROP TABLE q_123;

How to handle multiple one->many relationships?

I have a database with several tables, 5 of which are dedicated to specific publication types. Each of these 5 have a one->many relationship with a status table and a people table. All of these tables are tied together using a unique "pubid". I have a view which includes the pubid (for all 5 types), along with their associated keywords. When a user does a keyword search and the results span across more than 1 of those 5 publication type tables I am really not sure how to handle it.
If there was only a single publication type (so just one table that had a 1->many) it would be very easy to accomplish with a nested join, something like:
SELECT * FROM articles
INNER JOIN status ON articles.spubid = status.spubid
INNER JOIN people ON articles.spubid = people.spubid
WHERE people.saffil = 'ABC' ORDER BY people.iorder, articles.spubid;
In that example 'articles' is one of the 5 tables I mentioned that has a 1->many relationship. Lets say that the keyword search brings back results that include articles, books and papers. How can I achieve this same end with that many different tables? If I were to figure out how to use a JOIN in that case the Cartesian product would be so large that I think the overhead to parse it out into a usable format would be too high. What are my other options in this case?
Why are they in separate tables? Are the columns that different? And what columns do you want to return (never ever use select * in production especially with joins), are they different between the different types in your query?
If you can get the columns to be the same I suggest you use UNION ALL. Even if the columns are different by supplying all that you need in each part of the union statement (giving the value of null for those columns that set of tables doesn't have), you can still get what you want. Simplified code follows:
SELECT articlename, articlestatus, author, ISBN_Number
FROM articles
INNER JOIN status ON articles.spubid = status.spubid
INNER JOIN people ON articles.spubid = people.spubid
WHERE people.saffil = 'ABC'
UNION ALL
SELECT papername, paperstatus, author, null
FROM papers
INNER JOIN status ON papers.spubid = status.spubid
INNER JOIN people ON papers.spubid = people.spubid
WHERE people.saffil = 'ABC'
You could create a view that was the union of all the various tables. The tricky bit is to make sure that all the queries being UNIONed have the same fields, so you'll need to stub a few in each one. Here's a simplified example with only two tables:
CREATE VIEW AllTables AS
SELECT Afield1, Afield2, NULL as Bfield1, NULL as Bfield2 FROM Atable
UNION
SELECT NULL as Afield1, NULL as Afield2, Bfield1, Bfield2 FROM Btable;
You could use something other than NULL as the stub value if necessary, of course. Then you run your query against the view. If you need to vary the formatting according to the publication type, you could include the originating table as part of the view (ie, add "'magazine' AS publication_type" or something similar to each of your selects).
Perhaps you could create views for each of the 5 types (vwBook, vwArticle, etc.)
As you're searching, perhaps call into a stored proc that will use all 5 views using the keywords that you throw at it. Each of the 5 results could go into a table variable in your stored proc.
Modify, of course, as you see fit. Here's a broad stroke example:
create proc MySearch
#MySearchTerm varchar(50)
AS
DECLARE #SearchResultsTABLE
(
Type varchar(10) -- the view you found the result in.
,ID int -- the primary key of the Book record. whatever you want to link it back to the original
,FoundText varchar(512)
--etc
)
INSERT INTO #SearchResults(Type, ID, FoundText)
SELECT 'Articles', ID, SomeKeyField
FROM vwArticle
WHERE SomeKeyField LIKE '%' + #MySearchTerm + '%'
INSERT INTO #SearchResults(Type, ID, FoundText)
SELECT 'Book', ID, SomeKeyField
FROM vwBook
WHERE SomeKeyField LIKE '%' + #MySearchTerm + '%'
--repeat as needed with the 3 other views that you'd build
SELECT * FROM #SearchResults
I really don't like the table design here. However I guess redesigning the entire database from scratch is a bit too extreme.
Given the table design, I think you're going to have to go with a UNION and specify the columns in each table. I know it's a monster, but that's what happens when you design tables with lots of columns which are "almost" alike.
And HLGEM is right. Using "select *" in a permanently-stored query is really dangerous.
We ended up creating a very elaborate view which includes the 1-many tables as array columns in the view. This allows for a single query to be performed on a single view and all the required data is returned. The view definition is VERY complex but it is working like a champ, the real trick was using the ARRAY() function in PostgreSQL.