Hibernate JPA Criteria - how to join with subquery - sql-server

I have two tables Author and Book with relationship one-many.
Now I want to list all authors with total of books in a particular country.
I use SQL Sever, this is my query.
SELECT Author.id, Author.name, Author.age, subTbl.total
FROM Author INNER JOIN (SELECT Book.authorId, COUNT(*) AS total FROM Book GROUP BY Book.authorId) subTbl
ON Author.authorId = subTbl.authorId
WHERE Author.countryId = 'en';
I know that we can write this query in another way without using SubQuery but I want to try SubQuery with CriteriaQuery to write this query.
I have searched further, but there are only examples of SubQuery in where expression.

Related

Subquery is returning more than one value? Not getting a result set?

Write a SELECT statement that returns two columns: VendorName and LargestInv
(LargestInv is the correlation name of the subquery)
Subquery portion:
SELECT statement that returns the largest InvoiceTotal from the Invoices table (you will need to perform the JOIN within the subquery in one of the clauses).
Sort the results by LargestInv from largest to smallest.(Subquery Must be in the Select statement)
I have tried this but My subqueries returning more than one value
USE AP
SELECT VendorName, (SELECT MAX(InvoiceTotal) FROM Invoices JOIN Vendors
ON Invoices.VendorID = Vendors.VendorID
GROUP BY Invoices.VendorID) AS LargestInv
FROM Vendors
Your issue is scope.
The sub-query shouldn't be joining to the Vendor table if the goal is a correlated sub-query. The "correlated" part comes from joining the results of the inner query (the sub-query) to the outer query.
As written, you're finding VendorID inside the sub-query and the results aren't correlated to the outer query at all. Hence your error message.
SELECT
VendorName,
(SELECT MAX(InvoiceTotal)
FROM Invoices
WHERE Invoices.VendorID = Vendors.VendorID
) AS LargestInv
FROM Vendors
ORDER BY LargestInv DESC;
Edit (extended explanation):
A correlated sub-query isn't designed to pull up a full result set, like the sub-query you were writing at first. It's designed to go over to another table and use a value (or values) from the outer query to bring back a single result, one row at a time.
In this case, using the VendorID from the Vendors table, go over to Invoices, calculate a MAX value "WHERE" the VendorID in Invoices matches the VendorID ON THIS ROW, bring that single value back, then, next row, go back and do that again. And again and again.
It's one way to get the data, but it's not usually efficient. Later, though, you'll learn to use correlated sub-queries in (NOT) EXISTS clauses, and in that context they tend to be extremely efficient. Story for another day, but it's one reason the construct is important to know.
So, your way was good, because it was set based and would tend to be more efficient as a sub-query in the FROM clause, but this way, row by row, is important to understand conceptually.
This is how I would do it.
SELECT VendorName, LargestInv.MaxI
FROM Vendors
FROM (
SELECT VendorName, MAX(InvoiceTotal) as MaxI
FROM Invoices
JOIN Vendors ON Invoices.VendorID = Vendors.VendorID
GROUP BY VendorName
) AS LargestInv ON LargestInv.VendorName = Vendors.VendorName
Now having more than one in the sub-query won't give you an error and you can look at the results.

which approach is best to get data from multiple tables

I have 2 tables and suppose having bulk of data
Table1 Table2
Id Name Address Id Table1Id Parents_Name Address
1 ABC 123ABC 1 1 DDD Xyz
. ... ...... . . ... ...
. ... ...... . . ... ...
Now if i want solution in below format
Id Name Parents_Name
1 ABC DDD
. ... ...
. ... ...
then which one will be best
Subquery or join
Joins and subqueries are both be used to query data from different tables and may even share the same query plan, but there are many differences between them. Knowing the differences and when to use either a join or subquery to search data from one or more tables is key to mastering SQL.
Joins and subqueries are both used to combine data from different tables into a single result. They share many similarities and differences.
Subqueries can be used to return either a scalar (single) value or a row set; whereas, joins are used to return rows.
A common use for a subquery may be to calculate a summary value for use in a query. For instance we can use a subquery to help us obtain all products have a greater than average product price.
SELECT ProductID,
Name,
ListPrice,
(SELECT AVG(ListPrice)
FROM Production.Product) AS AvgListPrice
FROM Production.Product
WHERE ListPrice > (SELECT AVG(ListPrice)
FROM Production.Product)
There are two subqueries in this SELECT statement. The first’s purpose is to display the average list price of all products, the second’s purpose is for filtering out products less than or equal to the average list price.
Subquery Free Video Offer
Here the subquery is returning a single value which is then used filter out products.
Notice how the subqueries are queries unto themselves. In this example you could paste the subquery, without the parenthesis, into a query window and run it.
Contrast this with a join whose main purpose of a join is to combine rows from one or more tables based on a match condition. For example we can use a join display product names and models.
Select Product.Name,
ProductModel.Name as ModelName
FROM Production.product
INNER JOIN Production.ProductModel
ON Product.ProductModelID = ProductModel.ProductModelID
In this statement we’re using an INNER JOIN to match rows from both the Product and ProductModel tables. Notice that the column ProducModel.Name is available for use throughout the query.
The combined row set is then available by the select statement for use to display, filter, or group by the columns.
This is different than the subquery. There the subquery returns a result, which is immediately used.
Note that join is an integral part of the select statement. It can not stand on its own as a subquery can.
A subquery is used to run a separate query from within the main query. In many cases the returned value is displayed as a column or used in a filter condition such as where or having clause. When a subquery incorporates a column from the main query it is said to be correlated. In this way a sub query is somewhat like a join in that values from two or more tables can be compared.
Joins are used in the FROM clause of the WHERE statement; however, you’ll find subqueries used in most clauses such as the:
SELECT List – here a subqueries used to return single values are used.
WHERE clause– depending on the conditional operator you’ll see single value or row based subqueries.
FROM clause– It is typical to see row based result subqueries used here.
HAVING clause – In my experience scalar (single value) subqueries are used here.
Though joins and subqueries have many differences, they can be used to solve similar problems. In fact just because you write a SQL statement as a subquery doesn’t mean the DBMS executes as such.
you can refer to this link for more details:-
http://www.essentialsql.com/what-is-the-difference-between-a-join-and-subquery/
Asuming you want an INNER JOIN:
SELECT t1.Id
,t1.Name
,t2.Parents_Name
FROM table1 t1
INNER JOIN table2 t2
ON t2.Table1Id = t1.Id
But you could also use an OUTER JOIN to always show rows from table1 and show the matching rows from table2.
SELECT t1.Id
,t1.Name
,t2.Parents_Name
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON t2.Table1Id = t1.Id
You will want to use a join, which will almost certainly be much more efficient. A quick google with give you much more information than you need to learn about the different types of joins available and how to use them, such as https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Please create an index on the id of Table1 and Table1Id of Table2 and use this query.
Select t1.Id,
t1.Name,
t2.Parents_Name
from Table1 t1
inner join
Table2 t2 on t1.id=t2.Table1Id
IMHO, Join should be preferred considering query performance. Squbquery will require IN operator that is always a pain with bulk data. However it also depends in your indexing. Better you check both.

SQL Server : group all data by one column

I need some help in writing a SQL Server stored procedure. All data group by Train_B_N.
my table data
Expected result :
expecting output
with CTE as
(
select Train_B_N, Duration,Date,Trainer,Train_code,Training_Program
from Train_M
group by Train_B_N
)
select
*
from Train_M as m
join CTE as c on c.Train_B_N = m.Train_B_N
whats wrong with my query?
The GROUP BY smashes the table together, so having columns that are not GROUPED combine would cause problems with the data.
select Train_B_N, Duration,Date,Trainer,Train_code,Training_Program
from Train_M
group by Train_B_N
By ANSI standard, the GROUP BY must include all columns that are in the SELECT statement which are not in an aggregate function. No exceptions.
WITH CTE AS (SELECT TRAIN_B_N, MAX(DATE) AS Last_Date
FROM TRAIN_M
GROUP BY TRAIN_B_N)
SELECT A.Train_B_N, Duration, Date,Trainer,Train_code,Training_Program
FROM TRAIN_M AS A
INNER JOIN CTE ON CTE.Train_B_N = A.Train_B_N
AND CTE.Last_Date = A.Date
This example would return the last training program, trainer, train_code used by that ID.
This is accomplished from MAX(DATE) aggregate function, which kept the greatest (latest) DATE in the table. And since the GROUP BY smashed the rows to their distinct groupings, the JOIN only returns a subset of the table's results.
Keep in mind that SQL will return #table_rows X #Matching_rows, and if your #Matching_rows cardinality is greater than one, you will get extra rows.
Look up GROUP BY - MSDN. I suggest you read everything outside the syntax examples initially and obsorb what the purpose of the clause is.
Also, next time, try googling your problem like this: 'GROUP BY, SQL' or insert the error code given by your IDE (SSMS or otherwise). You need to understand why things work...and SO is here to help, not be your google search engine. ;)
Hope you find this begins your interest in learning all about SQL. :D

Doing a join with SOQL

Here is my SOQL problem.
Query 1:
Select
c.Date_Joined__c,
c.Email,
c.FirstName,
c.LastName,
c.regcode__c
from Contact c WHERE c.regcode__c ='XXXXXXXXX'
Query 2:
Select
p.Account__c,
p.Date__c,
p.Points__c,
p.Description__c,
p.Code__c
from Points__c p where p.Account__c ='YYYYYYYYYYYY' and (p.Points__c > 0)
Order by p.Date__c DESC
The relationship between the two queries is that c.regcode__c will have the same value as p.Code__c.
I want to combine Query1 and Query2, so c.regcode__c = p.Code__c
I'm stuck, I can't seem to get the syntax right for SOQL.
Is it even possible to do joins in the API?
You can't really create a join per se but you can do some filtering using a syntax similar to this:
SELECT Id FROM Contact WHERE c.RegCode__c IN (SELECT p.Code__c FROM Account)
As long as the subquery in the WHERE clause is only returning a single value and codes is a filterable field this should work. Also, this doesn't work if you were trying to filter by the same object (i.e. Account to Account). You can add more criteria to the account side to match your example queries.
Again, this isn't a true join so you can't put the account fields from your subquery. But you can at least filter down your contacts.

Using Full-Text Search in SQL Server 2008 across multiple tables, columns

I need to search across multiple columns from two tables in my database using Full-Text Search. The two tables in question have the relevant columns full-text indexed.
The reason I'm opting for Full-text search:
1. To be able to search accented words easily (cafè)
2. To be able to rank according to word proximity, etc.
3. "Did you mean XXX?" functionality
Here is a dummy table structure, to illustrate the challenge:
Table Book
BookID
Name (Full-text indexed)
Notes (Full-text indexed)
Table Shelf
ShelfID
BookID
Table ShelfAuthor
AuthorID
ShelfID
Table Author
AuthorID
Name (Full-text indexed)
I need to search across Book Name, Book Notes and Author Name.
I know of two ways to accomplish this:
Using a Full-text Indexed View: This would have been my preferred method, but I can't do this because for a view to be full-text indexed, it needs to be schemabound, not have any outer joins, have a unique index. The view I will need to get my data does not satisfy these constraints (it contains many other joined tables I need to get data from).
Using joins in a stored procedure: The problem with this approach is that I need to have the results sorted by rank. If I am making multiple joins across the tables, SQL Server won't search across multiple fields by default. I can combine two individual CONTAINS queries on the two linked tables, but I don't know of a way to extract the combined rank from the two search queries. For example, if I search for 'Arthur', the results of both the Book query and the Author query should be taken into account and weighted accordingly.
Using FREETEXTTABLE, you just need to design some algorithm to calculate the merged rank on each joined table result. The example below skews the result towards hits from the book table.
SELECT b.Name, a.Name, bkt.[Rank] + akt.[Rank]/2 AS [Rank]
FROM Book b
INNER JOIN Author a ON b.AuthorID = a.AuthorID
INNER JOIN FREETEXTTABLE(Book, Name, #criteria) bkt ON b.ContentID = bkt.[Key]
LEFT JOIN FREETEXTTABLE(Author, Name, #criteria) akt ON a.AuthorID = akt.[Key]
ORDER BY [Rank] DESC
Note that I simplified your schema for this example.
I had the same problem as you but it actually involved 10 tables (a Users table and several others for information)
I did my first query using FREETEXT in the WHERE clause for each table but the query was taking far too long.
I then saw several replies about using FREETEXTTABLE instead and checking for not nulls values in the key column for each table, but that took also to long to execute.
I fixed it by using a combination of FREETEXTTABLE and UNION selects:
SELECT Users.* FROM Users INNER JOIN
(SELECT Users.UserId FROM Users INNER JOIN FREETEXTTABLE(Users, (column1, column2), #variableWithSearchTerm) UsersFT ON Users.UserId = UsersFT.key
UNION
SELECT Table1.UserId FROM Table1 INNER JOIN FREETEXTTABLE(Table1, TextColumn, #variableWithSearchTerm) Table1FT ON Table1.UserId = Table1FT.key
UNION
SELECT Table2.UserId FROM Table2 INNER JOIN FREETEXTTABLE(Table2, TextColumn, #variableWithSearchTerm) Table2FT ON Table2.UserId = Table2FT.key
... --same for all tables
) fts ON Users.UserId = fts.UserId
This proved to be incredibly much faster.
I hope it helps.
I don't think the accepted answer will solve the problem. If you try to find all the books from a certain author and, therefore, use the author's name (or part of it) as the search criteria, the only books returned by the query will be those which have the search criteria in its own name.
The only way I see around this problem is to replicate the Author's columns that you wish to search by in the Book table and index those columns (or column since it would probably be smart to store the author's relevant information in an XML column in the Book table).
FWIW, in a similar situation our DBA created DML triggers to maintain a dedicated full-text search table. It was not possible to use a materialized view because of its many restrictions.
I would use a stored procedure. The full text method or whatever returns a rank which you can sort by. I am not sure how they will be weighted against eachother, but I'm sure you could tinker for awhile and figure it out. For example:
Select SearchResults.key, SearchResults.rank From FREETEXTTABLE(myColumn, *, #searchString) as SearchResults Order By SearchResults.rank Desc
This answer is well overdue, but one way to do this if you cannot modify primary tables is to create a new table with the search parameters added to one column.
Then create a full text index on that column and query that column.
Example
SELECT
FT_TBL.[EANHotelID] AS HotelID,
ISNULL(FT_TBL.[Name],'-') AS HotelName,
ISNULL(FT_TBL.[Address1],'-') AS HotelAddress,
ISNULL(FT_TBL.[City],'-') AS HotelCity,
ISNULL(FT_TBL.[StateProvince],'-') AS HotelCountyState,
ISNULL(FT_TBL.[PostalCode],'-') AS HotelPostZipCode,
ISNULL(FT_TBL.[Latitude],0.00) AS HotelLatitude,
ISNULL(FT_TBL.[Longitude],0.00) AS HotelLongitude,
ISNULL(FT_TBL.[CheckInTime],'-') AS HotelCheckinTime,
ISNULL(FT_TBL.[CheckOutTime],'-') AS HotelCheckOutTime,
ISNULL(b.[CountryName],'-') AS HotelCountry,
ISNULL(c.PropertyDescription,'-') AS HotelDescription,
KEY_TBL.RANK
FROM [EAN].[dbo].[tblactivepropertylist] AS FT_TBL INNER JOIN
CONTAINSTABLE ([EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn, #s)
AS KEY_TBL
ON FT_TBL.EANHotelID = KEY_TBL.[KEY]
INNER JOIN [EAN].[dbo].[tblCountrylist] b
ON FT_TBL.Country = b.CountryCode
INNER JOIN [EAN].[dbo].[tblPropertyDescriptionList] c
ON FT_TBL.[EANHotelID] = c.EANHotelID
In the code above [EAN].[dbo].[tblEanFullTextSearch], FullTextSearchColumn is the new table and column with the fields added, you can now do a query on the new table with joins to the table you want to display the data from.
Hope this helps

Resources