Select query with join - oracle

I have tables:
How can I select NEWS with concrete TAGS, for example with two TAGS?
It's my wrong variant:
SELECT DISTINCT news.news_id, news.CREATION_DATE, news.MODIFICATION_DATE, news.FULL_TEXT, news.TITLE, news.SHORT_TEXT
FROM
news
INNER JOIN
news_tags
ON news.news_id = news_tags.news_id
WHERE news_tags.TAG_ID = 1 AND news_tags.TAG_ID = 3;

If you want to get news with tags 1 and 3 you should check that a record with tag_id 1 and a record with tag_id 3 exists in the news_tags table. Right now you're asking for news whose tag is 1 and at the same time 3, which doesn't really make sense.
Something like this:
SELECT DISTINCT news.news_id, news.CREATION_DATE, news.MODIFICATION_DATE, news.FULL_TEXT, news.TITLE, news.SHORT_TEXT
FROM news INNER JOIN news_tags ON news.news_id = news_tags.news_id
WHERE EXISTS (SELECT 1
FROM news_tags
WHERE news_id = news.news_id
AND tag_id = 1)
AND EXISTS (SELECT 1
FROM news_tags
WHERE news_id = news.news_id
AND tag_id = 3);

SELECT DISTINCT news.news_id, news.CREATION_DATE, news.MODIFICATION_DATE, news.FULL_TEXT, news.TITLE, news.SHORT_TEXT
FROM
news
INNER JOIN
news_tags
ON news.news_id = news_tags.news_id
inner join Tags on Tags.Tag_Id = news_tags.Tag_Id
WHERE news_tags.TAG_ID = 1 AND news_tags.TAG_ID = 3;

Related

numtoyminterval get all employee who have not had review within 4 month of starting

I've been given task to find all employees who have not had a review within 4 month of starting employment, but I need to use numtoyminterval.
I think I almost have it, but I cannot seem to work out how to get all employees who have not have review within 4 month of starting employment.
My code below returns all records.
Can anyone help with this.
SELECT Employee.ID,
Employee.Surname,
DateJoined.StartDate,
Review.NextReviewDate
numtoyminterval( months_between(DateJoined.StartDate, Review.NextReviewDate), 'month') as "EmployeeNotReviewed"
FROM CompanyData
INNER JOIN
Employee ON CompanyData.EmployeeID = Employee.EmployeeID
INNER JOIN
DateJoined ON CompanyData.JoinedID = DateJoined.StartDate
INNER JOIN
Review ON CompanyData.ReviewID = Review.Id
SELECT Employee.ID,
Employee.Surname,
DateJoined.StartDate,
Review.NextReviewDate
FROM CompanyData
INNER JOIN
Employee ON CompanyData.EmployeeID = Employee.EmployeeID
INNER JOIN
DateJoined ON CompanyData.JoinedID = DateJoined.StartDate
INNER JOIN
Review ON CompanyData.ReviewID = Review.Id
WHERE MONTHS_BETWEEN( DateJoined.StartDate, Review.NextReviewDate ) >= 4
or
SELECT Employee.ID,
Employee.Surname,
DateJoined.StartDate,
Review.NextReviewDate
FROM CompanyData
INNER JOIN
Employee ON CompanyData.EmployeeID = Employee.EmployeeID
INNER JOIN
DateJoined ON CompanyData.JoinedID = DateJoined.StartDate
INNER JOIN
Review ON CompanyData.ReviewID = Review.Id
WHERE DateJoined.StartDate + NUMTOYMINTERVAL( 4, 'MONTH' )
<= Review.NextReviewDate
The first option is better - try having a start date on DATE '2015-10-30' (then adding 4 months will be 30th February which will throw an exception ORA-01839: date not valid for month specified).

Selecting rows that has exactly same data as other table

I have these tables:
Products, Articles, Product_Articles
Lets say, product_ids are: p1 , p2 article_ids are: a1 , a2 , a3
product_articles is:
(p1,a1)
(p1,a2)
(p2,a1)
(p2,a1)
(p2,a2)
(p2,a3)
How to query for product_id, which has only a1,a2, nothing less, nothing more?
UPDATED Try
SELECT p.*
FROM products p JOIN
(
SELECT product_id
FROM product_articles
GROUP BY product_id
HAVING COUNT(*) = SUM(CASE WHEN article_id IN (1, 2) THEN 1 ELSE 0 END)
AND SUM(CASE WHEN article_id IN (1, 2) THEN 1 ELSE 0 END) = 2
) q ON p.product_id = q.product_id
or
SELECT p.*
FROM products p JOIN
(
SELECT product_id, COUNT(*) a_count
FROM product_articles
WHERE article_id IN (1, 2)
GROUP BY product_id
HAVING COUNT(*) = 2
) a ON p.product_id = a.product_id JOIN
(
SELECT product_id, COUNT(*) total_count
FROM product_articles
GROUP BY product_id
) b ON p.product_id = b.product_id
WHERE a.a_count = b.total_count
Here is SQLFiddle demo for both queries
This is an example of a "set-within-sets" subquery. I advocate using aggregation with a having clause for the logic, because this is the most general way to express the relationships.
The idea is that you can count the appearance of the articles within a product (in this case) in a way similar to using a where statement. The code is a bit more complex, but it offers flexibility. In your case, this would be:
select pa.product_id
from product_articles pa
group by pa.product_id
having sum(case when pa.article_id = 'a1' then 1 else 0 end) > 0 and
sum(case when pa.article_id = 'a2' then 1 else 0 end) > 0 and
sum(case when pa.article_id not in ('a1', 'a2') then 1 else 0 end) = 0;
The first two clauses count the appearance of the two articles, making sure that there is at least one occurrence of each. The last counts the number of rows without those two articles, making sure there are none.
You can see how this easily generalizes to more articles. Or to queries where you have "a1" and "a2" but not "a3". Or where you have three of four of specific articles, and so on.
I believe this can be done entirely using relational joins, as follows:
SELECT DISTINCT pa1.PRODUCT_ID
FROM PRODUCT_ARTICLES pa1
INNER JOIN PRODUCT_ARTICLES pa2
ON (pa2.PRODUCT_ID = pa1.PRODUCT_ID)
LEFT OUTER JOIN (SELECT *
FROM PRODUCT_ARTICLES
WHERE ARTICLE_ID NOT IN (1, 2)) pa3
ON (pa3.PRODUCT_ID = pa1.PRODUCT_ID)
WHERE pa1.ARTICLE_ID = 1 AND
pa2.ARTICLE_ID = 2 AND
pa3.PRODUCT_ID IS NULL
SQLFiddle here.
The inner join looks for products associated with the articles we care about (articles 1 and 2 - produces product 1 and 2). The left outer looks for products associated with articles we don't care about (anything article except 1 and 2) and then only accepts products which don't have any unwanted articles (i.e. pa3.PRODUCT_ID IS NULL, indicating that no row from pa3 was joined in).

How to create (probably)nested query?

I have 3 entities Patient with id , Workers with id , profession and PatientDeclaration with patient_id(fk) and workers_id(fk). I want to get workers_id from PatientDeclaration when I have patient_id and profession. Something like that,
'SELECT c FROM SurgeryPatientBundle:PatientDeclaration c WHERE c.patient = ?1 AND c.patient =(SELECT w FROM SurgeryWorkersBundle:Workers WHERE p.profession = ?2)'
I suposse that I have create nested query?
edit
Solved I make diffrent query
SELECT w.id FROM SurgeryWorkersBundle:Workers w JOIN w.patientdeclaration p WHERE w.profession = ?1 AND p.patient = ?2
You can use a subquery
SELECT
c
FROM
SurgeryPatientBundle:PatientDeclaration c
JOIN
c.patient p
WHERE
p = ?1
AND
p.id IN (SELECT w.id FROM SurgeryWorkersBundle:Workers WHERE p.profession = ?2)

GROUP BY and HAVING in linq

I want to convert this code to linq:
select t1.title, COUNT(*)as num
from t1 INNER join t2 on t2.gId = t1.Id
group by t1.title, t1.cId
having t1.cId = 2
I tried this below code:
from p in db.t1s join r in db.t2s on p.Id equals r.gId
where p.cId == 2
group p by p.title into g
select new{ name = from o in g select o.title, num = g.Count()}
But this doesn't return COUNT correctly.
please guide me how can I solve the problem
thanks
Without sample data its hard to get it right, but try this snippet
from p in db.t1s
join r in db.t2s on p.Id equals r.gId
where p.cId == 2
group p by new {p.title, p.cId} into grouped
select new{ name = grouped.Key.title, num = grouped.Count()}
Also, note that this sql:
select t1.title, COUNT(*)as num
from t1 INNER join t2 on t2.gId = t1.Id
group by t1.title, t1.cId
having t1.cId = 2
Will always return 1 as result of COUNT(*). The reason is that you have filtering t1.cId = 2 and grouping by t1.cId as second parameter.

How to use GroupBy properly in LINQ?

I have 4 tables: Post, Category, Relation and Meta
A category can contains multiple posts, and the relation between them is stored in Relation table. A post then can has many extra info that are stored in Meta table. I want to list all post with categories and extra infos, then group them by post's ID.
I have the following query
select p.ID, p.Title, t.Name, m.Key, m.Value from Post p
left join Relation r on p.ID = r.Child
left join Category c on r.Parent = c.ID
left join Meta m on p.ID = m.Object
where m.Type = 'news'
order by p.ID
and with these sample data:
Post
ID Title
1 A
Category
ID Name
1 Tips
2 Tricks
Meta
ID Object Key Value
1 1 Key1 Value 1
2 1 Key2 Value 2
Relation
ID Child Parent
1 1 1
2 1 2
then the result will be
PostID Title Category Key Value
1 A Tips Key1 Value1
1 A Tips Key2 Value2
1 A Tricks Key1 Value1
1 A Tricks Key2 Value2
and I expected the result to be
PostID Title Categories Meta
1 A Tips, Tricks Key1=Value1, Key2=Value2
I wonder if we can convert the query from SQL to LINQ to Entities with EF v4 and the result is stored in a class like this
class Result
{
long ID,
string Title,
List<string> Categories,
Dictionary<string, string> Meta
}
Any helps would be appreciated.
What's the final result you expect from the query
I personally prefer to write the query like
var q = from r in Relation
join p in Post on r.Child equals p.ID
join t in Term on r.Parent equals t.ID
let x = new { p.ID, p.Title, t.Name }
group x by x.ID into g
select g;
this way I think (not sure) the sql generated will be simpler
Now that you're wanting to use EntityFramework, you would merely need to set up you database, edmx with a Result table with an ID and a Title, then Category and Meta tables. Then add one-to-many relationships from the Result table to each the Category and Meta tables.
I'm not 100% sure what you're trying to do, but obviously if you're grouping, the results have to be grouped by anything in the resultset, or be aggregated data. This query will retrieve your results and group by PostId, PostTitle, and CategoryName, generating a single SQL Statement:
var query = from p in Posts
from r in Relations
.Where(r => p.ID == r.Child)
.DefaultIfEmpty()
from c in Categories
.Where(c => r.Parent == c.ID)
.DefaultIfEmpty()
group p by new {ID = p.ID, Title = p.Title, Name = c.Name} into z
select new { ID = z.Key.ID, Title = z.Key.Title, Name = z.Key.Name };
Here is the SQL Generated by this statement:
SELECT [t3].[ID], [t3].[Title], [t3].[value] AS [Name]
FROM (
SELECT [t0].[ID], [t0].[Title], [t2].[Name] AS [value]
FROM [Post] AS [t0]
LEFT OUTER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
LEFT OUTER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
) AS [t3]
GROUP BY [t3].[ID], [t3].[Title], [t3].[value]
Here is the SQL Generated by your original statement:
SELECT [t0].[ID] AS [Key]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
GROUP BY [t0].[ID]
GO
-- Region Parameters
DECLARE #x1 Int SET #x1 = 1
-- EndRegion
SELECT [t0].[ID], [t0].[Title], [t2].[Name]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
WHERE ((#x1 IS NULL) AND ([t0].[ID] IS NULL)) OR ((#x1 IS NOT NULL) AND ([t0].[ID] IS NOT NULL) AND (#x1 = [t0].[ID]))
GO
-- Region Parameters
DECLARE #x1 Int SET #x1 = 2
-- EndRegion
SELECT [t0].[ID], [t0].[Title], [t2].[Name]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
WHERE ((#x1 IS NULL) AND ([t0].[ID] IS NULL)) OR ((#x1 IS NOT NULL) AND ([t0].[ID] IS NOT NULL) AND (#x1 = [t0].[ID]))

Resources