How can you add a select based on a conditional to the doctrine query builder?
I'd like to replicate SQL similar to this:
select p.id, p.id = 3 as first_result
from problem p
order by first_result desc, p.id
As per docs you could use expression and mark this column as HIDDEN (not to include in results) but can be use in query like in your case to order results
DQL would look like
SELECT p, p.id = 3 AS HIDDEN first_result
FROM YourProblemEntity p
ORDER BY first_result DESC, p.id
Or you can introduce CASE expression
SELECT p,
CASE WHEN p.id = 3 THEN 1 ELSE 0 END AS HIDDEN first_result
FROM YourProblemEntity p
ORDER BY first_result DESC, p.id
See DQL SELECT Examples
Related
I have the following tables in Oracle 12c:
objects (about 600 K lines)
attributes (about 10 M lines)
I need to transpose objects' attributes into another table. The idea is shown in the picture below.
To do so now I use a lot of "JOINs" like:
SELECT
o.id,
o.name,
a1.value as attr_1,
a2.value as attr_2,
a3.value as attr_3,
a4.value as attr_4,
a5.value as attr_5
FROM objects o
LEFT JOIN attributes a1 ON a1.obj_id = o.id AND a1.attr_id = 1
LEFT JOIN attributes a2 ON a2.obj_id = o.id AND a2.attr_id = 2
LEFT JOIN attributes a3 ON a3.obj_id = o.id AND a3.attr_id = 3
LEFT JOIN attributes a4 ON a4.obj_id = o.id AND a4.attr_id = 4
LEFT JOIN attributes a5 ON a5.obj_id = o.id AND a5.attr_id = 5
I have some queries with up to 20 attributes so I have to JOIN "10 M lines"-table 20 times.
It works but it takes a lot of time.
Do you have any good ideas how to organize it better?
One possibility, as mentioned in comments, is to use the PIVOT option on the SELECT. I am not clear what your concern is about this -- are you just saying you want to determine the actual resulting column names yourself? You can easily alias the columns after the PIVOT operation.
Before PIVOT existed, the standard method I used and saw others use to accomplish it was like this:
SELECT obj_id,
MAX(CASE WHEN attr_id = 1 THEN value ELSE NULL) AS attr_1,
MAX(CASE WHEN attr_id = 2 THEN value ELSE NULL) aS attr_2,
... etc. ...
FROM attributes
GROUP BY obj_id
For the full query, you could put this subquery in a CTE and join that with objects.
Note this doesn't necessarily mean that Oracle will execute the entire subquery before doing the join. In your case it might, since I assume every row in objects has corresponding rows in attributes. But if you had a filter on obj_id in the query, it might filter on that first then do the grouping. In any case, I'd certainly expect this to be more efficient than joining many times.
You can use level and connect by to generate the SQL like below.But if you give the exact SQL skeleton we can make use of user_tab_Cols to generate the SQL.
SELECT 'select o.id,o.name, 'sql_text
FROM dual
UNION ALL
SELECT 'a.'
||LEVEL
||'.values as attr_'
||LEVEL
||',' sql_text
FROM dual
CONNECT BY LEVEL <= 5
UNION ALL
SELECT 'FROM objects o '
FROM dual
UNION ALL
SELECT 'LEFT JOIN attributes a'
||LEVEL
||' ON a'
||LEVEL
||'.obj_id = o.id AND a'
||LEVEL
||'.attr_id = '
||LEVEL
FROM dual
CONNECT BY LEVEL <= 5
Unfortunately this database has a ton of duplicate email addresses in it. I need to do a query and return only unique emails, doesn't really matter which one.
The query I have looks like this, can't really figure out what to add to not get duplicate emails returned. Can anyone think of anything?
select c.cid, c.email, c.uuid, e.code
from c
inner join e on e.cid = c.cid
where regexp_like(c.email, '\.net$', 'i');
-- Adding some additional info on request
The above query returns the following results, where you can see there are duplicates. I'm interested in only returning one row per unique email address.
3478|cust1#cust1.net|ouskns;dhf|1
3488|cust2#cust2.net|jlsudo;uff|0
3598|cust3#cust3.net|dl;udjffff|1
3798|cust1#cust1.net|osuosdujff|1
3888|cust1#cust1.net|odsos7jfff|1
-- Solution, thanks Mathguy
select cid, email, uuid, code
from
(select c.cid, c.email, c.uuid, e.code, row_number() over (partition by
c.email order by null) as rn
from c
inner join e on e.cid = c.cid
where regexp_like(c.email, '\.net$', 'i')
)
where rn = 1;
If it works as is and the only problem is the duplicates, you can change c.email to MAX(c.email) as email in the select clause, and add a group by clause to group by the other columns included in select.
EDIT: (actually I should delete the original answer since the OP clarified his question was quite different from what he seemed to ask originally - but that would also delete the comments... so editing instead)
If your query produces the desired results, but now you must pick just one random row per email address, you can try this:
select cid, email, uuid, code
from
( -- .... copy your select query here
-- ADD one column to the select line like so:
-- select c.cid, c.uuid, c.email, e.code,
-- row_number() over (partition by c.email order by null) as rn
-- ....
)
where rn = 1;
Using DISTINCT :
select DISTINCT c.email
from c
inner join e on e.cid = c.cid
where regexp_like(c.email, '\.net$', 'i');
Or using GROUP BY (and you get the number of dups in the cnt column)
select c.email, count(*) as cnt
from c
inner join e on e.cid = c.cid
where regexp_like(c.email, '\.net$', 'i')
GROUP BY c.email;
SELECT TOP (5)
Sales.Product, Sales.Product_Price, COUNT(*) AS CNT,
Products.Category, Products.IMG_URL, Products.Rate_Avg
FROM
Sales
INNER JOIN
Products ON Sales.Product = Products.Product
GROUP BY
Sales.Product, Sales.Product_Price,
Products.Category, Products.IMG_URL, Products.Rate_Avg
HAVING
(COUNT(*) > 1)
ORDER BY CNT DESC
Most of that query has a 1-to-1 correspondence to the equivalent linq-to-sql expression. Though the TOP (5) part needs to be added to the end.
(from s in db.Sales
join p in db.Products on s.Product equals p.Product
group s by new { s.Product, s.Product_Price, p.Category, p.IMG_URL, p.Rate_Avg } into g
where g.Count() > 1
orderby g.Count() descending
select new
{
g.Key.Product,
g.Key.Product_Price,
CNT = g.Count(),
g.Key.Category,
g.Key.IMG_URL,
g.Key.Rate_Avg,
}).Take(5)
I know we can get distinct on one column using following query:
I know we can get distinct on one column using following query:
SELECT *
FROM (SELECT A, B, C,
ROW_NUMBER() OVER (PARTITION BY B ORDER BY A) AS RowNumber
FROM MyTable
WHERE B LIKE 'FOO%') AS a
WHERE a.RowNumber = 1
I have used similar sql query in my case where i am joining multiple tables but my project is in mvc4 and i need linq to entity equivalent of the same. Here is my code:
select * from
(
select fp.URN_No,
ROW_NUMBER() OVER
(PARTITION BY pdh.ChangedOn ORDER BY fp.CreatedOn)
as num,
fp.CreatedOn, pdh.FarmersName, pdh.ChangedOn, cdh.Address1, cdh.State, ich.TypeOfCertificate, ich.IdentityNumber, bdh.bankType, bdh.bankName,
pidh.DistrictId, pidh.PacsRegistrationNumber, idh.IncomeLevel, idh.GrossAnnualIncome
from MST_FarmerProfile as fp inner join PersonalDetailsHistories as pdh on fp.personDetails_Id = pdh.PersonalDetails_Id
inner join ContactDetailsHistories as cdh on fp.contactDetails_Id = cdh.ContactDetails_Id
inner join IdentityCertificateHistories as ich on fp.IdentityCertificate_Id = ich.IdentityCertificate_Id
inner join BankDetailsHistories as bdh on fp.BankDetails_Id = bdh.BankDetails_Id
left join PacInsuranceDataHistories as pidh on fp.PacsInsuranceData_Id = pidh.PacsInsuranceData_Id
left join IncomeDetailsHistories as idh on fp.IncomeDetails_Id = idh.IncomeDetails_Id
where URN_No in(
select distinct MST_FarmerProfile_URN_No from PersonalDetailsHistories where MST_FarmerProfile_URN_No in(
select URN_No from MST_FarmerProfile where (CreatedOn>=#fromDate and CreatedOn<= #toDate and Status='Active')))
)a where a.num=1
Use this linq query after getting result from sql. p.ID is be your desire distinct column name
List<Person> distinctRecords = YourResultList
.GroupBy(p => new { p.ID})
.Select(g => g.First())
.ToList();
I am trying to select a table from my database based on top 5 values from another table and met a roadblock.
here is the version without the top 5 values :
from d in Deals
from f in FacebookUserCategories
from s in SubCategories
where s.FacebookCategoryId == f.FacebookCategoryId
&& f.FacebookUserId == 1437585390
orderby f.Count descending
select d
However , what i need is to select Deals based on the top 5 Ids from SubCategories table, meaning i have to use a Take operator.
The below linq will help me achieve this :
(from f in FacebookUserCategories
from s in SubCategories
where s.FacebookCategoryId == f.FacebookCategoryId
orderby f.Count descending
select s.Id).Take(5)
Is there anyway for me to select the Deals table which has a SubCategoryId as a join from here?
Just to recap...i could write the sql.. it would be like this :
SELECT t1.* FROM Deal t1
INNER JOIN (
SELECT TOP 5 t2.Id FROM FacebookUserCategory , SubCategory t2
WHERE FacebookUserId = '1437585390'
AND FacebookUserCategory.FacebookCategoryId = t2.FacebookCategoryId
ORDER BY Count DESC) tbl
ON t1.SubCategoryId = tbl.Id
Try this, Use Join for all 3 tables, You use Join for only 2 tables, why not use Join for 3rd table also.
var result = from d in deals
let top5Counts =
(from f in FacebookUserCategories
join s in SubCategories on f.FacebookCategoryId equals s.FacebookCategoryId
where f.FacebookUserId == 1437585390
orderby f.Count descending
select s.Id).Take(5)
where top5Counts.Contains(d.SubCategoryId.Value)
select d;