I need to calculate Median for several fields in a query and group it by one of the column. Is there a way to calculate Median easily in SQL Server 2008 R2? I am having trouble calculating it in 2008 R2.
Table structure:
PatientName (need to calculate count group by PatientType)
PatientType (should be used to group the query by),
minutes1,
minutes2,
minutes3,
minutes4,
minutes5
End Result:
PatientCount (Group by PatientType),
Median For minutes1 (Group by PatientType),
Median For minutes2 (Group by PatientType),
Median For minutes3 (Group by PatientType),
Median For minutes4 (Group by PatientType),
Median For minutes5 (Group by PatientType)
You could try this:
SELECT PatientType, minutes1=(
SELECT AVG(1.0 * minutes1)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes1 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes2=(
SELECT AVG(1.0 * minutes2)
FROM
(
SELECT t3.minutes2, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes2 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes3=(
SELECT AVG(1.0 * minutes1)
FROM
(
SELECT t3.minutes3, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes3 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes4=(
SELECT AVG(1.0 * minutes4)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes4 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
), minutes5=(
SELECT AVG(1.0 * minutes5)
FROM
(
SELECT t3.minutes1, rn = ROW_NUMBER() OVER (ORDER BY t3.minutes1), c.c
FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t3
CROSS JOIN (SELECT c = COUNT(*) FROM (SELECT minutes5 FROM Table t2 WHERE t1.PatientType=t2.PatientType) t4) AS c
) AS x
WHERE rn IN ((c + 1)/2, (c + 2)/2)
)
FROM Table t1
GROUP BY PatientType
and there is probably a much better way, and it could likely be optimized quite a bit.
Related
In this query, I want to use with-statement. I have a subquery that calculates A union all B and I want to use it with with-statement. But when I use with-statement I face the error that says "table or view does not exist".
what surprises me is when I replace the first part with with-statement it works correctly. But when I replace the second part, I face this error!!
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||''||deposit.CUSTOMER_NUM||'-
'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days
AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS
START_DATE,
MAIN_7.AMOUNT
AS TOTAL_AMOUNT,
MAIN_7.TRN_Count
AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(Active_Time_Table.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(Active_Time_Table.AMOUNT) AS AMOUNT,
Count(Active_Time_Table.AMOUNT) AS TRN_Count
from
(
Select F.DEPOSIT_KEY,
SUM (F.AMOUNT) AS TRN_AMOUNT,
MIN (F.EFFECTIVE_DATE) AS TRN_Start_DATE
from
(
A
union all
B
)F
Group by (F.DEPOSIT_KEY)
Having ( SUM (F.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and
Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
(
A
union all
B
)Active_Time_Table
on (Trans_Table.DEPOSIT_KEY = Active_Time_Table.DEPOSIT_KEY and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and
Active_Time_Table.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY ,
Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(Active_Time_Table.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
***********************************************************
with rep as
(A union all B)
select
deposit.BRNCH_COD||'-'||deposit.DP_TYPE_COD||'-
'||deposit.CUSTOMER_NUM||'-'||deposit.DEPOSIT_SERIAL AS DEPOSIT_NUMBER,
deposit.IBAN AS IBAN,
deposit.CURRENCY_DESC AS DEPOSIT_CURRCOD,
deposit.BRNCH_COD AS BRNCH_COD,
MAIN_7.Still_Days AS Still_Lenght,
to_char(MAIN_7.Startdate, 'yyyy/mm/dd' ,'nls_calendar=persian') AS START_DATE,
MAIN_7.AMOUNT AS TOTAL_AMOUNT,
MAIN_7.TRN_Count AS TRN_Count
from
(
select Trans_Table.DEPOSIT_KEY AS DEPOSIT_KEY,
Trans_Table.TRN_Start_DATE AS Startdate,
MAX(rep.EFFECTIVE_DATE) AS Lastdate,
H.PASSIVE_DAYS AS Still_Days,
SUM(rep.AMOUNT) AS AMOUNT,
Count(rep.AMOUNT) AS TRN_Count
from
(
Select rep.DEPOSIT_KEY,
SUM (rep.AMOUNT) AS TRN_AMOUNT,
MIN (rep.EFFECTIVE_DATE) AS TRN_Start_DATE
from
rep
Group by (rep.DEPOSIT_KEY)
Having ( SUM (rep.AMOUNT) >10000000000)
)Trans_Table
inner join
H
on (Trans_Table.DEPOSIT_KEY = H.DEPOSIT_KEY and Trans_Table.TRN_Start_DATE-1 = H.EFFECTIVE_DATE)
inner join
rep rep
on (Trans_Table.DEPOSIT_KEY = rep.DEPOSIT_KEY and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE< 4 and rep.EFFECTIVE_DATE - Trans_Table.TRN_Start_DATE>=0)
group by ( Trans_Table.DEPOSIT_KEY , Trans_Table.TRN_Start_DATE,H.PASSIVE_DAYS)
Having (SUM(rep.AMOUNT)) > 10000000000
)MAIN_7
inner join dimamldeposit deposit
on deposit.DEPOSIT_KEY = MAIN_7.DEPOSIT_KEY
That's a lot of code, but - to make it simple, I'd suggest you use WITH factoring clause as the first command, include all tables you use into it, and then - as the final SELECT - fetch data from all those CTEs. Something like this:
with
a as (select ... from ...),
b as (select ... from ...),
f as (select ... from ...),
...
select a.col1, b.col2, f.col3
from a join b on a.id = b.id
left join f on f.id = b.id
where ...
I have tables like these:
INSERT INTO listings
(id, external_id, variation_id, product_id) VALUES
(101, '9900001', '9900001var1', 1),
(102, '9900001', '9900001var2', 4),
(103, '9900002', '9900002var1', 1),
(104, '9900002', '9900002var2', 2),
(105, '9900003', '9900003var1', 3),
(106, '9900003', '9900003var2', 4);
INSERT INTO products
(id, price) VALUES
(1, 101),
(2, 100),
(3, 100),
(4, 102);
Which means that there are 3 listings (9900001, 9900002, 9900003) with 2 products each (1, 4), (1, 2) and (3, 4) respectively.
What I need is to retrieve one single row for each listing, with the id (not the price) of the product with the highest price in that listing.
So, the desired output would be:
id | external_id | variation_id | product_id
[ANY] 9900001 [ANY] 4
[ANY] 9900002 [ANY] 1
[ANY] 9900003 [ANY] 4
The closest I got to the desired answer was with this query:
SELECT
p.id AS product_id_max,
p.price AS product_price_max,
MAX(p.price) AS product_price_max_max,
listings.*
FROM listings
INNER JOIN (
-- Subquery tested above:
SELECT DISTINCT pp3.* FROM
(SELECT MAX(p2.price) as max_price
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS p
ON p.id = listings.product_id
-- WHERE MAX(p.price) = p.price
GROUP BY external_id
-- HAVING MAX(p.price) = p.price
ORDER BY product_price_max DESC
Uncommenting the WHERE clause throws an error, uncommenting the HAVING clause returns less rows than desired. Leavin both commented give the correct rows but wrong values in the product_id column.
Fiddle: http://sqlfiddle.com/#!9/d58d665/54/0
I figured it out:
SELECT
listings.*,
max_p.product_id AS max_product_id
FROM listings
INNER JOIN (
SELECT DISTINCT max_external_id as external_id, pp3.id as product_id FROM
(SELECT MAX(p2.price) as max_price, l2.external_id as max_external_id
FROM products p2
INNER JOIN listings l2 ON l2.product_id = p2.id
GROUP BY l2.external_id) pp2
INNER JOIN
(SELECT p3.* FROM products p3 ) pp3
ON
pp2.max_price = pp3.price
ORDER BY pp3.price DESC
) AS max_p
ON max_p.external_id = listings.external_id
GROUP BY listings.external_id
As tested here:
http://sqlfiddle.com/#!9/d58d665/53/0
I have been having trouble finding the result for this problem.
Below are my table structure details:
studios
(
studio_id,
location
)
photo_sessions
(
session_id,
studio_id,
cust_id,
session_length,
session_date
)
customer
(
cust_id,
cus_first,
cus_last,
emailid
)
order
(
order_id,
cust_id,
order_description,
amount
)
package_order
(
package_order_id,
order_id,
package_id,
price,
quantity
)
package
(
package_id,
package_name
)
I would like to find which package is ordered most often at each location.
I tried this query,
SELECT
p.package_name,
s.location,
count(p.package_id)
FROM package p,
package_order po,
order_table o,
customer c,
photo_sessions ps,
studios s
WHERE p.package_id=po.package_id
and po.order_id=o.order_id
and o.cust_id=c.cust_id
and c.cust_id=ps.cust_id
and ps.studio_id=s.studio_id
GROUP BY p.package_name,
s.location
HAVING COUNT (p.package_id)=
(
SELECT MAX(mycount)
FROM (
SELECT package_id, COUNT(package_id) as mycount
FROM package_order
GROUP BY package_id
) as most_order
);
I am not sure it gives the right result. Any help will be appreciated.
You can do this with window functions:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount,
row_number() over(partition by s.location order by count(p.package_id) desc) AS rn
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte
WHERE rn = 1
PS: you use Sql Server 2012 but joining with old style deprecated syntax. It is time to forget about old one.
EDIT:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte c1
CROSS APPLY(SELECT MAX(mycount) mycount FROM cte c2 WHERE c1.location = c2.location) ca
WHERE c1.mycount = ca.mycount
I want to do the following in LINQ to SQL:
Select count(*) as count_1,
(select count(*) from tableName2) as count_2 FROM tableName
Where x = y
The result should be
Column 1 | column 2
--------------------
50 34
What you need to do is something like this:
select
(select count(*)
from tableName
where x = y) as count_1,
(select count(*)
from tableName2) as count_2
I have two tables
table1
c1t1 c2t1
1 saanu
3 abc
table2
c1t2 c2t2
2 val2
4 val4
I have to find out the values of c2t1 and c2t2 for the minimum and maximum value of c1t1 and c1t2 with one line command.
For the above example I have to find saanu and val4
I had a very similar problem and solved it with UNION ALL. The minimum of the aColumn column in tables aTable1, ... , aTableN can be computed as:
SELECT Min(aColumn)
FROM (
SELECT aColumn FROM aTable1 UNION ALL
SELECT aColumn FROM aTable2 UNION ALL
...
SELECT aColumn FROM aTableN) t;
You should be able to do Min in each of the inner selects, but I haven't found out how to do that!
One approach:
select max(case c1 when min1 then c2 end) c2_first,
max(case c1 when max1 then c2 end) c2_last
from (select c1t1 c1, c2t1 c2 from table1
union all
select c1t2 c1, c2t2 c2 from table2) u
cross join
(select min(min11, min12) min1, max(max11, max12) max1 from
(select min(c1t1) min11, max(c1t1) max11 from table1) t1
cross join
(select min(c1t2) min12, max(c1t2) max12 from table2) t2) m
SQLFiddle here.
1)
SELECT c2t1
FROM table1
ORDER BY c1t1 ASC LIMIT 1
2)
SELECT c2t2
FROM talbe2
ORDER BY c1t2 DESC LIMIT 1