PostgreSQL : Cannot use column alias in CASE statement - sql

I cannot use column alias in CASE clause in the following example:
SELECT
((SELECT SUM(t2.amount) FROM trans t2 WHERE u.mail = t2.paid_to)-
(SELECT SUM(t2.amount) FROM trans t2 WHERE u.mail = t2.paid_by)) AS "balance",
(CASE WHEN balance < u.credit_limit THEN 'YES' ELSE 'NO' END) AS "result"
FROM user u
LEFT JOIN trans t ON u.mail = t.paid_to OR u.mail = t.paid_by
How can I solve this problem?
Another question, should I use a different alias for inner selects (t2) or can I also use the same alias (t) as the outer select for trans table?

It is problematic to use the alias "balance" inside of a CASE statement because you try to use alias as a field within the same query and Postgresql restricts it.
You can try to write a subquery.
As DB schema wasn't provided, I couldn't test this query:
WITH t AS (
SELECT
((SELECT SUM(amount) FROM trans WHERE u.mail = paid_to)-
(SELECT SUM(amount) FROM trans WHERE u.mail = paid_by)) AS balance,
u.credit_limit
FROM user u
LEFT JOIN trans t ON u.mail = t.paid_to OR u.mail = t.paid_by
)
SELECT t.balance,
CASE WHEN t.balance < t.credit_limit THEN 'YES' ELSE 'NO' END AS result
FROM t;

Related

Re-writing EXISTS as JOIN or a subquery in Oracle

I have a query which is very costly and taking more than an hour to execute. I tried converting the EXISTS clause to join but I am stuck, can anyone help?
The purpose is to find duplicate product within a unique space id. FLAT_TABLE consists of 5 million records.
Query:
select
tbl1.product,
tbl1.status,
tbl1.reservation,
tbl1.unique_space_id
FROM
schema1.flat_table tbl1
WHERE
tbl1.status = 'Active'
AND tbl1.product = 'Cage'
AND EXISTS
(SELECT 1
FROM schema1.flat_table tbl2
WHERE tbl2.product = 'Cage'
AND tbl2.status = 'Active'
AND tbl2.reservation <> 'Space Reserved'
AND tbl1.unique_space_id = tbl2.unique_space_id
GROUP BY tbl2.unique_space_id
HAVING COUNT (1) > 1
);
You can use analytical function count as follows:
select * from
(select tbl1.product, tbl1.status, tbl1.reservation, tbl1.unique_space_id,
count(case when tbl1.reservation <> 'Space Reserved' then 1 end)
over(partition by tbl1.unique_space_id) as cnt
FROM schema1.flat_table tbl1
WHERE tbl1.status = 'Active' AND tbl1.product = 'Cage')
where cnt > 1
You could rewrite your query as an inner join to the current exists subquery. The join would have the effect of filtering in the same way the exists clause was behaving.
SELECT DISTINCT
tbl1.product,
tbl1.status,
tbl1.reservation,
tbl1.unique_space_id
FROM schema1.flat_table tbl1
INNER JOIN
(
SELECT unique_space_id
FROM schema1.flat_table
WHERE product = 'Cage' AND
status = 'Active' AND
reservation <> 'Space Reserved'
GROUP BY unique_space_id
HAVING COUNT(*) > 1
) tbl2
ON tbl2.unique_space_id = tbl1.unique_space_id
WHERE
tbl1.status = 'Active' AND
tbl1.product = 'Cage';
Here is a more concise version using COUNT as an analytic function, along with a QUALIFY clause;
SELECT DISTINCT product, status, reservation, unique_space_id
FROM schema1.flat_table
WHERE status = 'Active' AND product = 'Cage'
QUALIFY COUNT(CASE WHEN reservation <> 'Space Reserved' THEN 1 END)
OVER (PARTITION BY unique_space_id) > 1;

SQL case return more than 1 row write a string

I have a subquery in SELECT and sometimes it returns more than one row. I want to solve the problem like this:
when more than 1 row write a string like 'multi'
otherwise use the value description from comment table
Query:
select
s.id,
(select description from comment c where c.id = s.id)
from student s;
thanks.
You can join, aggregate, and use a conditional expression:
select
s.id,
case when min(c.description) <> max(c.description)
then 'multi'
else min(c.description)
end description
from student s
left join comment c on c.id = s.id
group by s.id
You can also do this with a subquery, which avoids outer aggregation (it is handy if you need more columns from students):
select
s.*,
(
select
case when min(c.description) <> max(c.description)
then 'multi'
else min(c.description)
end
from comment c
where c.id = s.id
) description
from student s

Getting error tb_sales_person_source.id is invalid in the select list in SQL Server

I am new to SQL Server, I have below query which is working fine in Mysql server, but it is not working in SQL Server, I get an error:
tb_sales_person_source.id is invalid in the select list
Can anyone please help me how can I resolve this error ?
SELECT
tb_sales_person_source.id,
tb_sales_person_source.name,
tb_sales_person_source.display_name,
tb_sales_person_source.mapped_sales_person_source_id,
tb_sales_person_source.company_id,
tb_sales_person_source.gm_created,
tb_sales_person_source.gm_modified,
COUNT(tb_Episode.id) AS total_soc,
SOCDate, MonthSOC
FROM
tb_Episode
JOIN
tb_sales_person_source ON tb_sales_person_source.id = tb_Episode.sales_referral_source_id
WHERE
(BranchID = '238' OR BranchID = '239' OR BranchID = '240' OR BranchID = '241')
AND tb_Episode.CustID = '27'
AND PayerType = 'Ep'
AND SOC = 1
AND SOCDate >= '2016-04-01'
AND SOCDate < '2017-5-01'
GROUP BY
sales_referral_source_id, MonthSOC
ORDER BY
tb_sales_person_source.id ASC, tb_Episode.SOCDate ASC;
In SQL server, you must have to add all the columns of "SELECT" in "Group by" apart from the column which is used in the aggregate function
SELECT tb_sales_person_source.id
,tb_sales_person_source.NAME
,tb_sales_person_source.display_name
,tb_sales_person_source.mapped_sales_person_source_id
,tb_sales_person_source.company_id
,tb_sales_person_source.gm_created
,tb_sales_person_source.gm_modified
,count(tb_Episode.id) AS total_soc
,SOCDate
,MonthSOC
FROM tb_Episode
JOIN tb_sales_person_source ON tb_sales_person_source.id = tb_Episode.sales_referral_source_id
WHERE (
BranchID = '238'
OR BranchID = '239'
OR BranchID = '240'
OR BranchID = '241'
)
AND tb_Episode.CustID = '27'
AND PayerType = 'Ep'
AND SOC = 1
AND SOCDate >= '2016-04-01'
AND SOCDate < '2017-5-01'
GROUP BY sales_referral_source_id
,MonthSOC
,tb_sales_person_source.id
,tb_sales_person_source.NAME
,tb_sales_person_source.display_name
,tb_sales_person_source.mapped_sales_person_source_id
,tb_sales_person_source.company_id
,tb_sales_person_source.gm_created
,tb_sales_person_source.gm_modified
,SOCDate
ORDER BY tb_sales_person_source.id ASC
,tb_Episode.SOCDate ASC
It is impossible to accurately re-write your query until you update it to make it clear which table each column comes from.
The important piece of information you need to be aware of, however, is that when using GROUP BY every field in the SELECT must either have an aggregate function around it (MIN(), or MAX(), or SUM(), etc, etc), or be mentioned in the GROUP BY.
This means that the following is NOT valid SQL...
SELECT
t1.some_id,
t1.name,
t1.whatever,
COUNT(t2.id),
SUM(t2.value)
FROM
t1
INNER JOIN
t2
ON t2.some_id = t1.some_id
GROUP BY
t1.some_id
Instead you need one of the following...
SELECT
t1.some_id ,
t1.name,
t1.whatever,
COUNT(t2.id),
SUM(t2.value)
FROM
t1
INNER JOIN
t2
ON t2.some_id = t1.some_id
GROUP BY
t1.some_id,
t1.name,
t1.whatever
Or...
SELECT
t1.some_id,
MAX(t1.name),
MAX(t1.whatever),
COUNT(t2.id),
SUM(t2.value)
FROM
t1
INNER JOIN
t2
ON t2.some_id = t1.some_id
GROUP BY
t1.some_id
The same is true even if you are grouping by a column from table 2.
So, this is invalid too...
SELECT
t1.some_id,
t1.name,
t2.a_date,
COUNT(t2.id),
SUM(t2.value)
FROM
t1
INNER JOIN
t2
ON t2.some_id = t1.some_id
GROUP BY
t2.a_date
This time, however, you have an extra option. Use a sub-query to group up the data in table 2 first...
SELECT
t1.some_id,
t1.name,
t2_agg.a_date,
t2_agg.count_rows,
t2_agg.total_value
FROM
t1
INNER JOIN
(
SELECT
some_id,
a_date,
COUNT(t2.id) AS count_rows,
SUM(t2.value) AS total_value
FROM
t2
GROUP BY
some_id,
a_date
)
t2_agg
ON t2_agg.some_id = t1.some_id
If you fully qualify your query (so I can see which table every column comes from) then I can show you how to use this method to suit your exact case.
Finally i resolved my query, here is my query, thanks to all of you for your help
SELECT tb_sales_person_source.id, tb_sales_person_source.name, tb_sales_person_source.display_name, count(tb_Episode.id) as total_soc, MonthSOC
FROM tb_Episode
JOIN tb_sales_person_source ON tb_sales_person_source.id = tb_Episode.sales_referral_source_id
WHERE ( BranchID = '238' or BranchID = '239' or BranchID = '240' or BranchID = '241')
AND tb_Episode.CustID = '27'
AND PayerType = 'Ep'
AND SOC = 1
AND SOCDate >= '2016-04-01'
AND SOCDate < '2017-5-01'
GROUP BY tb_sales_person_source.id, tb_sales_person_source.name, tb_sales_person_source.display_name, sales_referral_source_id, MonthSOC
ORDER BY tb_sales_person_source.id asc

How can I get value from above row with same ID if row is null?

I'm new with SQL and I encountered this.
Here's a screenshot
My question is how can I make all the NULL on primary_payer_id get the value above only if they have same ClientID and ActionCode IS NOT NULL. FYI CustomColumn is only a copy of primary_payer_id ALSO I attached my code here below.
Here's my code:
SELECT ci.client_id AS ClientID,
ci.primary_payer_id,
ci.effective_date AS EffectiveDate,
ci.action_code_id AS ActionCode,
cc.item_description AS ItemDesc,
ap.description AS IDescription,
ci.deleted
FROM census_item ci
LEFT JOIN common_code cc ON ci.adt_tofrom_id = cc.item_id
LEFT JOIN ar_lib_payers ap ON ci.primary_payer_id = ap.payer_id
WHERE ci.deleted = 'N'
There might be a more efficient method, but this will work:
with t as (
<your query here>
)
select t.*,
(case when t.actioncode is not null and t.clientid is null
then tprev.clientid
else t.clientid
end) as new_clientid
from t outer apply
(select top 1 tprev.*
from t tprev
where tprev.clientid = t.clientid and
tprev.effectivedate < t.effectivedate
order by tprev.effecctivedate desc
) tprev;

Used Joined tables in select statment

I was wondering if it is possible to use a bound joined table in a CASE statment when declaring a column in a select statment. I have included a simplified example of my problem in the snippet below.Any ideas? Thanks!
SELECT M.MID
,[Count] = CASE (SELECT COUNT(*) FROM Refund R2
WHERE R2.RefundID = R.RefundID) = 1
THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID
The "WHERE R2.RefundID = R.RefundID says that the "R.RefundID cannot be bound.
If you are using SQL Server 2005 or later, you could try a different approach:
SELECT
M.MID,
[Count] = CASE COUNT(*) OVER (PARTITION BY R.RefundID)
WHEN 1 THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID
You have a bad alias. You have an R but not an R2, which is referenced:
SELECT M.MID
,[Count] = CASE WHEN (SELECT COUNT(*) FROM ReferralTypeKey R2
WHERE R2.RefundID = R.RefundID) = 1
THEN 'One'
ELSE 'Many'
END
FROM #temp T
JOIN Refund R ON R.RefundID = T.RefundID