How use .Count() in LINQ To SQL? - linq-to-sql

How can I translate this TSQL query to LINQ To SQL?
Select p3.Alias, Count(p3.Alias) as [Count] from Persons p1
INNER JOIN Addresses a ON p1.Id = a.Person
INNER JOIN Persons p2 ON a.CityX = p2.Id
INNER JOIN ContrAgents ca ON p2.Id = ca.Slave
INNER JOIN Persons p3 ON ca.Master = p3.Id
where p1.Type >9 and p1.Type<16
group by p3.Alias
I want to get 2 things: data in p3.Alias and data in p.Count().
List<cNumberOfObject> number = (from p1 in vt.Persons
join a in vt.Addresses on p1.Id equals a.Person
join p2 in vt.Persons on a.CityX equals p2.Id
join ca in vt.ContrAgents on p2.Id equals ca.Slave
join p3 in vt.Persons on ca.Master equals p3.Id
where p1.Type>9 && p1.Type<16
group p3 by p3.Alias into p
select new cNumberOfObject
{
// Subject = p3.Alias,
Number = p.Count()
}).ToList();

The result of a group by is an IGrouping. You can access the value of the column you grouped your objects by accessing the Key property on the IGrouping:
var number = (from p1 in vt.Persons
join a in vt.Addresses on p1.Id equals a.Person
join p2 in vt.Persons on a.CityX equals p2.Id
join ca in vt.ContrAgents on p2.Id equals ca.Slave
join p3 in vt.Persons on ca.Master equals p3.Id
where (p1.Type > 9 && p1.Type < 16)
group p3 by p3.Alias into p
select new cNumberOfObject
{
Subject = p.Key, // The alias
Number = p.Count()
}).ToList()

Related

How to filter nonaggregated query results by an aggregated column?

I'm creating a price comparison service. Products from one Site are compared to products from one or more Sites. Products are matched from one Site to another using a ProductMatch table:
Given the following query to extract products, together with their matches:
SELECT
p1.id AS p1_id, p1.name AS p1_name, p1.price AS p1_price,
p2.id AS p2_id, p2.name AS p2_name, p2.price AS p2_price,
m.time
FROM Product p1
LEFT JOIN ProductMatch m ON m.fromProduct_id = p1.id
LEFT JOIN Product p2 ON m.toProduct_id = p2.id
WHERE p1.site_id = 1;
How can I filter products whose price (p1.price) is lower than the minimum competitor price (MIN(p2.price))?
Using subqueries, here's how I would do it:
SELECT
p1.id AS p1_id, p1.name AS p1_name, p1.price AS p1_price,
p2.id AS p2_id, p2.name AS p2_name, p2.price AS p2_price,
m.time
FROM Product p1
LEFT JOIN ProductMatch m ON m.fromProduct_id = p1.id
LEFT JOIN Product p2 ON m.toProduct_id = p2.id
WHERE p1.id IN (
SELECT x.id FROM (
SELECT _p1.id, _p1.price
FROM Product _p1
JOIN ProductMatch _m ON _m.fromProduct_id = _p1.id
JOIN Product _p2 ON _m.toProduct_id = _p2.id
WHERE _p1.site_id = 1
GROUP BY _p1.id
HAVING _p1.price < MIN(_p2.price)
) x
);
Is it possible to simplify this query to not use subqueries?
My concerns:
it feels weird to repeat the exact same joins in the subquery
I have concerns about the performance of subqueries on larger data sets
subqueries don't play very well with my ORM
With MIN() window function inside a CTE which will be filtered:
WITH cte AS (
SELECT
p1.id AS p1_id, p1.name AS p1_name, p1.price AS p1_price,
p2.id AS p2_id, p2.name AS p2_name, p2.price AS p2_price,
m.time,
MIN(p2.price) OVER (PARTITION BY p1.id) AS min_price
FROM Product p1
LEFT JOIN ProductMatch m ON m.fromProduct_id = p1.id
LEFT JOIN Product p2 ON m.toProduct_id = p2.id
WHERE p1.site_id = 1
)
SELECT
p1_id, p1_name, p1_price,
p2_id, p2_name, p2_price,
time
FROM cte
WHERE p1_price < min_price

Combine left join with commas

So I've got this SQL code :
SELECT *
FROM A a1, AP ap1, P p1, M m1
LEFT JOIN F f1 ON f1.id_f = p1.f1
LEFT JOIN C c1 ON p1.c_id = c1.c_id
LEFT JOIN S s1 on p1.saison_id = s1.s_id
WHERE a1.a_type NOT IN (1)
AND a1.type_c IN (1,2)
AND ap1.a_id = a1.achats_id
AND p1.p_id = ap1.products_id
AND p1.m_id = m1.m_id
ORDER BY a_id ASC
And I get this error :
#1054 - Unknown column 'p1.f1' in 'on clause'
So I have no idea why doesn't it recognize p1.f1 on line 3. Any ideas?
You would simply use proper JOIN or INNER JOIN syntax:
SELECT *
FROM A a1 JOIN
AP ap1
ON ap1.a_id = a1.achats_id JOIN
P p1
ON p1.p_id = ap1.products_id JOIN
M m1
ON p1.m_id = m1.m_id LEFT JOIN
F f1
ON f1.id_f = p1.f1 LEFT JOIN
C c1
ON p1.c_id = c1.c_id LEFT JOIN
S s1
ON p1.saison_id = s1.s_id
WHERE a1.a_type NOT IN (1) AND a1.type_c IN (1, 2)
ORDER BY a1.a_id ASC;
Voila! Problem solved.

How to Change my Select SQL to Update SQL?

I have managed to write the following SQL that gives me all records that have the same value in _price, _regular_price & _sale_price.
I need to update _sale_price on these records only to ' ' (nothing / empty)
Here is my working Select:
SELECT p.id, p.post_title, p1.meta_key, p1.meta_value, p2.meta_key, p2.meta_value, p3.meta_key, p3.meta_value
FROM sm_posts p
INNER JOIN sm_postmeta p1 ON p.id = p1.post_id
AND p1.meta_key = '_price'
INNER JOIN sm_postmeta p2 ON p.id = p2.post_id
AND p2.meta_key = '_regular_price'
INNER JOIN sm_postmeta p3 ON p.id = p3.post_id
AND p3.meta_key = '_sale_price'
WHERE p1.meta_value = p2.meta_value AND p1.meta_value = p3.meta_value
I need to create an Update from this but cant figure it out.
So far I have this but its not working:
UPDATE sm_postmeta2,
(
SELECT p.id, p.post_title, p1.meta_key, p1.meta_value, p2.meta_key, p2.meta_value, p3.meta_key, p3.meta_value
FROM sm_posts p
INNER JOIN sm_postmeta2 p1 ON p.id = p1.post_id
AND p1.meta_key = '_price'
INNER JOIN sm_postmeta2 p2 ON p.id = p2.post_id
AND p2.meta_key = '_regular_price'
INNER JOIN sm_postmeta2 p3 ON p.id = p3.post_id
AND p3.meta_key = '_sale_price'
WHERE p1.meta_value = p2.meta_value AND p1.meta_value = p3.meta_value
GROUP BY p1.ID
)
SET sm_postmeta2.meta_value = ''
WHERE sm_postmeta2.meta_value.id = p1.id
Please can someone help, i am new to SQL and it took me forever just to get the joins working. lol
Thank you for taking the time to help me.
Your error means that you must alias the subquery. However, you don't want to put the subquery in the UPDATE clause. If you do, MySQL either won't allow it, or it will update the temporary table resulting from the subquery, i.e. the changes wouldn't persist. Instead, you can INNER JOIN on the subquery to get the rows you want to update.
Since you're just using the subquery to determine the rows to update, you don't need to SELECT all the same values as before. Instead, you can just SELECT the primary key for the records you want to update.
Here's an example:
UPDATE sm_postmeta2 INNER JOIN
(
SELECT DISTINCT p3.meta_id
FROM sm_posts p
INNER JOIN sm_postmeta2 p1 ON p.id = p1.post_id
AND p1.meta_key = '_price'
INNER JOIN sm_postmeta2 p2 ON p.id = p2.post_id
AND p2.meta_key = '_regular_price'
INNER JOIN sm_postmeta2 p3 ON p.id = p3.post_id
AND p3.meta_key = '_sale_price'
WHERE p1.meta_value = p2.meta_value AND p1.meta_value = p3.meta_value
) p_tmp ON sm_postmeta2.meta_id = p_tmp.meta_id
SET sm_postmeta2.meta_value = ''

Select a product from filters

I have a problem with a query:
I have 3 tables:
products (id, name)
settings (id, name)
product_setting (product_id, setting_id)
for example: I would like to select only the products you have selected filters!
I do this:
SELECT p. *, s.id as setting
FROM Products p
INNER JOIN product_setting p2 ON (p.id = p2.product_id)
INNER JOIN settings s ON (s.id = p2.setting_id)
WHERE s.id IN (1,2)
but I get all products that have the 'setting' id = 1 OR id = 2.
How to get only those products that have those 'setting' (AND)?
thanks!!
SELECT p.*, s.id as setting
FROM Products p
INNER JOIN product_setting p2 ON (p.id = p2.product_id)
INNER JOIN settings s ON (s.id = p2.setting_id)
WHERE s.id IN (1,2)
GROUP BY p.id
HAVING COUNT(*)=2; // size of IN()
This seems like over kill but...
SELECT p. *, s.id as setting
FROM Products p
INNER JOIN product_setting p2 ON (p.id = p2.product_id)
INNER JOIN settings s ON (s.id = p2.setting_id)
INNER JOIN settings s2 ON (s.id = p2.setting_id)
WHERE
s.id = 1
AND s2.id = 2

only returning records when s.id = u.summary_id

select
s.id, s.description, s.improvement, s.previous_year_id,
s.current_year_id, s.first_name, s.last_name, s.username,
s.finding, s.action, s.share, s.learned, s.timestamp,
d.title as department_title,
group_concat(g.title SEPARATOR \' | \') as strategic_goals,
y1.year as current_year_title, y2.year as previous_year_title,
u.summary_id, u.file_name as file_name
from
summary s, year y1, year y2, strategic_goal_entries sge,
goal g, department d, uploads u
where
s.id = sge.summary_id
and
s.current_year_id = y1.id
and
s.previous_year_id = y2.id
and
sge.goal_id = g.id
and
s.id = u.summary_id
and
s.department_id = d.id
and
s.department_id = '4'
group by
s.id
This only returns records from the summary table that has a relating record in the uploads table (s.id = uploads.summary_id) that contain a value within the uploads.summary_id field
I want to return all records, whether or not it has a file associated with it.
Any help is appreciated.
Suggest refactoring this SQL query to use ANSI joins. To achive your goal, you'd want a LEFT JOIN instead:
SELECT /*your columns*/
from summary s
INNER JOIN year y1 ON s.current_year_id = y1.id
INNER JOIN year y2 ON s.previous_year_id = y2.id
INNER JOIN strategic_goal_entries sge ON s.id = sge.summary_id
INNER JOIN goal g ON sge.goal_id = g.id
INNER JOIN department d ON s.department_id = d.id
LEFT JOIN uploads u ON s.id = u.summary_id
WHERE s.department_id = '4'
group by s.id