LINQ with sub select query using sum and group by? - linq

Can anyone help me with a LINQ query. I have converted most of it but i have a sub query in the stored procedure and i can't figure out how to do it..
basically this is the old stored procedure (truncated for ease)
SELECT M.Period AS 'Period' ,
C.Code AS 'Group' ,
C.ClientCode AS 'Code' ,
C.ClientName AS 'Name' ,
( SELECT SUM(Amount) AS Expr1
FROM M
WHERE ( ClientCode = C.ClientCode )
GROUP BY ClientCode
) AS 'Amount' ,
As you can see from above the sub query is like so
SELECT SUM(Amount) AS Expr1
FROM M
WHERE ( ClientCode = C.ClientCode )
GROUP BY ClientCode
) AS 'Amount'
So i have done all my joins and i have this so far and it works.
var test = from c in C join h in H on c.Code
equals h.Code join m in M on c.ClientCode
equals m.ClientCode
select new
{
Period=m.Period,
Group=c.Code,
Code= c.ClientCode,
Name= c.ClientName,
<-- Here is where i need the sub select query above -->
};
But i am at a loss of how to do the subquery. The name of the column will be Amount as you are able to see in the old stored procedure.
I would appreciate any feedback or help
THanks

Im not sure on that last part of your SQL query but I am assuming something like this
SELECT M.Period AS 'Period' ,
C.Code AS 'Group' ,
C.ClientCode AS 'Code' ,
C.ClientName AS 'Name' ,
( SELECT SUM(Amount) AS Expr1
FROM M
WHERE ( ClientCode = C.ClientCode )
GROUP BY ClientCode
) AS 'Amount'
from C inner join M on C.ClientCode = M.ClientCode
so your LINQ will be this
var test = from c in db.C
select new {
Period = c.M.Period,
Group = c.Code,
Code = c.ClientCode,
Name = c.ClientName,
Amount = (System.Int32)
((from m0 in db.M
where
m0.ClientCode == c.ClientCode
group m0 by new {
m0.ClientCode
} into g
select new {
Expr1 = (System.Int32)g.Sum(p => p.Amount)
}).First().Expr1)
}

Related

convert subquery to use Cases and Join

I have a query which is working fine. I want to convert it to use Cases and Join.
SELECT id, Ticket_id, serial_no, operator,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'COMPUTER_TYPE') as COMPUTER_TYPE,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'BRAND') as BRAND,
(SELECT value FROM Forms_Details where FORM_ID = cv.id and status = 'ACTIVE' and key = 'MODEL') as MODEL,
status, datetime
FROM Form cv
where status = 'ACTIVE' order by id desc;
If you want to join, then join. What keeps you from doing so?
SELECT
f.id,
f.Ticket_id,
f.serial_no,
f.operator,
ct.value AS computer_type,
b.value AS brand,
m.value AS model,
f.status,
f.datetime
FROM form f
LEFT JOIN forms_details ct ON ct.form_id = f.id AND ct.status = 'ACTIVE' AND ct.key = 'COMPUTER_TYPE'
LEFT JOIN forms_detailswhere b ON b.form_id = f.id AND b.status = 'ACTIVE' AND b.key = 'BRAND'
LEFT JOIN forms_detailswhere m ON m.form_id = f.id AND m.status = 'ACTIVE' AND m.key = 'MODEL'
WHERE f.status = 'ACTIVE'
ORDER BY f.id DESC;
Or, in order not to read the same table twice, you can use conditional aggregation to get the values from the table:
SELECT
f.id,
f.Ticket_id,
f.serial_no,
f.operator,
ct.value AS computer_type,
fdw.brand,
fdw.model,
f.status,
f.datetime
FROM form f
LEFT JOIN forms_details ct ON ct.form_id = f.id AND ct.status = 'ACTIVE' AND ct.key = 'COMPUTER_TYPE'
LEFT JOIN
(
SELECT
form_id,
MAX(CASE WHEN key = 'BRAND' THEN value END) AS brand,
MAX(CASE WHEN key = 'MODEL' THEN value END) AS model
FROM forms_detailswhere
WHERE status = 'ACTIVE' AND key IN ('BRAND', 'MODEL')
GROUP BY form_id
) fdw ON fdw.form_id = f.id
WHERE f.status = 'ACTIVE'
ORDER BY f.id DESC;
You can PIVOT and then join:
SELECT cv.id,
cv.Ticket_id,
cv.serial_no,
cv.operator,
fd.computer_type,
fd.brand,
fd.model,
cv.status,
cv.datetime
FROM Form cv
LEFT OUTER JOIN (
SELECT *
FROM (
SELECT form_id, key, value
FROM Form_Details
WHERE status = 'ACTIVE'
)
PIVOT (
MAX(value)
FOR key IN (
'BRAND' AS brand,
'MODEL' AS model,
'COMPUTER_TYPE' AS computer_type
)
)
) fd
ON (cv.id = fd.form_id)
where cv.status = 'ACTIVE'
order by id desc;

How can I join these two select queries into one query?

this is my first time posting, so I am sure I will get a number of things wrong. Do not hesitate to correct me and I will do everything I can to clarify.
In Oracle SQL Developer, I am trying to take two separate SELECT statements and combine them to get one row of results. Unfortunately, because this is sensitive data, I am unable to give any results from the statements individually, but instead, just the SQL statements themselves. I suspect I should be able to join these two on the field "emplid" but just cannot get there. Any help is greatly appreciated! Here is the code below, please mind the syntax :)
1st Select statement is giving me a list of people that were paid in 2017:
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
And 2nd Select statement would be a list of the deductions taken for the employees that were identified in the first statement:
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
Ideally, what I'd like to do is put in a value in place of 'XXXXXX' and get one row of data with the two combined statements.
Thanks everyone!
To do this, we stick each SELECT statement into a subquery and give that subquery an alias to refer to in the main queries select statement:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
) t1
INNER JOIN
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
) t2 ON
t1.empid = t2.empid
We just treat each derived table/subquery as it's own table and join them on empid. You can tweak the SELECT statement at the top as needed.
This is similar to creating a view for both sql statements and then referencing the views in a third sql statement.
An alternative way of doing this is to use CTE (Common Table Expressions) to house the separate sql. There's no performance advantage here, but you might find it easier to read.
WITH t1 as
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
),
t2 AS
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
)
SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON
t1.empid = t2.empid
Basically you do something like
select blah, blah.. (your second query )
AND G.EMPLID IN ( SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
)
So basically I have used your first query in you second query. I removed the DISTINCT, as its not needed.
I hope that makes sense.

How do I "Order by" more than on column?

This is my query:
SELECT count(oi.id) imgCnt, o.*,
IF(pricet=2,c.currency_value*o.attributes_36*o.price,
c.currency_value*o.price) AS pprice, od.title, oi.image,
MIN(oi.id), ( c.currency_value * o.price ) AS fprice,
ag.agent_name, DATE_FORMAT( o.date_added, '%d-%m-%Y') as dadded
FROM i_offers_12 o
LEFT JOIN i_agents ag ON o.agents_id = ag.id
LEFT JOIN i_currencies c ON o.currencies_id = c.id
LEFT JOIN i_offers_details od ON ( o.id = od.offers_id AND od.languages_id = 1 )
LEFT JOIN i_offers_images oi ON ( oi.offers_id = o.id AND oi.o_id = '12' )
WHERE ( o.offer_status='active' OR o.offer_status='sold')
AND actions_id = '1'
AND c.id = o.currencies_id
AND o.counties_id = '2'
AND o.cities_id = '3'
GROUP BY o.id
ORDER BY dadded
DESC
I want to sort after dadded(which is of type date) and offer_status(which is of type enum).
I want to display first, all of the elements which have offer_status = 'active' and sort by dadded and after that all of the elements which have offer_status = 'sold' and sort also by dadded. How can I do that? thx
The fields you want to sort on MUST be part of the select statement:
SELECT count(oi.id) imgCnt, o.*,
IF(pricet=2,c.currency_value*o.attributes_36*o.price,
c.currency_value*o.price) AS pprice, od.title, oi.image,
MIN(oi.id), ( c.currency_value * o.price ) AS fprice,
ag.agent_name, DATE_FORMAT( o.date_added, '%d-%m-%Y') as dadded ,
offer_status
FROM i_offers_12 o
LEFT JOIN i_agents ag ON o.agents_id = ag.id
LEFT JOIN i_currencies c ON o.currencies_id = c.id
LEFT JOIN i_offers_details od ON ( o.id = od.offers_id AND od.languages_id = 1 )
LEFT JOIN i_offers_images oi ON ( oi.offers_id = o.id AND oi.o_id = '12' )
WHERE ( o.offer_status='active' OR o.offer_status='sold')
AND actions_id = '1'
AND c.id = o.currencies_id
AND o.counties_id = '2'
AND o.cities_id = '3'
AND o.offer_status='active'
GROUP BY o.id
ORDER BY offer_status, dadded
DESC
Note that you normally should group by ALL non summarized fields (o.*,
IF(pricet=2,c.currency_value*o.attributes_36*o.price,
c.currency_value*o.price) AS pprice, od.title, oi.image, ( c.currency_value * o.price ) AS fprice,
ag.agent_name, DATE_FORMAT( o.date_added, '%d-%m-%Y') as dadded ,
offer_status)
MySQL is not enforcing it, but other DB like Oracle does.
You can use a comma, like
ORDER BY supplier_city DESC, supplier_state ASC;
I believe you can write the SQL with
ORDER BY offer_status, dadded

Dynamic query to dynamic data

I am new to the oracle database, I am trying to execute the following query
select o.id as ovaid ,
(case when(select count(m.cid) from ovamapper m where m.id = o.id and m.solutionid = 1)>0 then 1 else 0 end) as sol1,
(case when(select count(m.cid) from ovamapper m where m.id = o.id and m.solutionid = 2)>0 then 1 else 0 end) as sol1,
(case when(select count(m.cid) from ovamapper m where m.id = o.id and m.solutionid = 3)>0 then 1 else 0 end) as sol1 from ovatemplate o order by o.id
Instead of static values for solutionid , I would like to select it from other table.
Any help on this is really appreciated
you could use
join
to table that contain the solutionid. ex
Select * from ovatemplate JOIN solutiontable ON (solutiontable.ovaid=ovatempate.ovaid)
after that, change the static values to solutionid
Try this query
select o.id as ovaid ,
count(case when solutionid = 1 then m.cid else null end) as sol1 ,
count(case when solutionid = 2 then m.cid else null end) as sol2 ,
count(case when solutionid = 3 then m.cid else null end) as sol3
from ovamapper m , ovatemplate o
where m.id = o.id
group by o.id
order by o.id
If you dont need the aggregations as columns you should probably do that instead
select o.id as ovaid , solutionid , count(*) as sol
from ovamapper m , ovatemplate o
where m.id = o.id
and m.solutionid in (1,2,3)
group by o.id , solutionid
order by o.id

oracle : joining subquery with outer query

I have two queries with a union as follows:
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = 400
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = 400
group by h1.payment_date, h1.customer_no
Now, I want to use this union in another query.
select * from (
select '00/00/0000' as payment_date , h1.customer_no
from payments h1
where not exists ( select 1 from payments h2 where h2.customer_no = h1.customer_no and h2.ctype = 'CASH' )
and h1.customer_no = p.customer_no
group by h1.customer_no
union
select to_char(h1.payment_date, 'MM/DD/YYYY') , h1.customer_no
from payments h1 inner join ( select customer_no, max(payment_date ) as max_date from payments where ctype = 'CASH' group by customer_no ) subQ
on ( h1.customer_no = subQ.customer_no
and h1.payment_date = subQ.max_date )
and h1.customer_no = p.customer_no
group by h1.payment_date, h1.customer_no ) sq,
payments p
where p.customer_no = 400
and sq.customer_no = p.customer_no
when I run this, I get ORA-00904: "P"."CUSTOMER_NO": invalid identifier. I need to join h1.customer_no to outer queries customer_no.
I have seen some queries with rank but I couldn't quite figure it out. How do I join the inner query with the outer query?
thanks in advance.
Does your payments table have a customer_no column? That seems to be what your error is indicating.
As for how to join the subqueries, you might want to look into factored subqueries. You can do:
WITH z AS (
SELECT ...
UNION
SELECT ...
), y AS (
SELECT ...
)
SELECT ...
FROM y
JOIN z ON y.x = z.x
JOIN some_other_table t ON z.a = t.a

Resources