Using created column in select statement twice - sql

I have a big problem with this query in SQL.
select distinct
b.*,
case
when b.Cash > b2.Cash
then ((b.Cash - b2.Cash) / b.Cash) * 100
end as Increased,
('Cash Increased by' + convert(VARCHAR(20), Increased))) as
Case
from
Accounting b
join
(…
In select statement I created column Increased. Then I want to created another column Case with the following value Cash Increased by… (value from Increased column).
My question is how can I do it in one select statement?

You have two options
Use this query as a subquery and do the concatenation in the outer query
You have to copy-paste the CASE..WHEN into the concatenations
Subquery
SELECT
*
, ('Cash Increased by' + convert(VARCHAR(20), Increased))) AS CASE
FROM (
SELECT DISTINCT
b.*
, CASE
WHEN b.Cash > b2.Cash THEN ((b.Cash - b2.Cash) / b.Cash) * 100
END AS Increased
FROM
Accounting b JOIN (...)
) SubQuery
Copy the CASE part
SELECT DISTINCT
b.*
, CASE
WHEN b.Cash > b2.Cash THEN ((b.Cash - b2.Cash) / b.Cash) * 100
END AS Increased
, (
'Cash Increased by' + CONVERT(VARCHAR(20),
CASE
WHEN b.Cash > b2.Cash THEN ((b.Cash - b2.Cash) / b.Cash) * 100
END)
) AS CASE
FROM
Accounting b JOIN (...)
NOTE
Do not forget to escape (or change) the alias for the concatenation. The CASE is a reserved word in most DMBS!
NOTE 2 Next time please mention the DBMS you are using!

Related

SQL CASE WHEN ELSE not working in AWS Athena

I have the script below setup in AWS Athena, the goal is to replace some budget numbers (total) with 0 if they are within a certain category (costitemid). I'm getting the following error in AWS Athena and could use some advice as to why it isn't working. Is the problem that I need to repeat everything in the FROM and GROUP BY in the WHEN and ELSE? Code below the error. Thank you!
SYNTAX_ERROR: line 6:9: 'projectbudgets.projectid' must be an aggregate expression or appear in GROUP BY clause
This query ran against the "acorn-prod-reports" database, unless qualified by the query. Please post the error message on our forum or contact customer support with Query Id: 077f007b-61a0-4f6b-aa1f-dd38bb401218
SELECT
CASE
WHEN projectbudgetlineitems.costitemid IN (462561,462562,462563,462564,462565,462566,478030) THEN (
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(((0 * projectbudgetlineitems.unitcost) * (projectbudgetlineitems.costshare * 1E-2))) total
)
ELSE (
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(((projectbudgetlineitems.quantity * projectbudgetlineitems.unitcost) * (projectbudgetlineitems.costshare * 1E-2))) total
)
END
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears projectbudgetyears ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems projectbudgetlineitems ON (projectbudgetyears.id = projectbudgetlineitems.projectbudgetyearid))
--WHERE (((projectbudgetlineitems.costitemid <> 478030) AND (projectbudgetlineitems.costitemid < 462561)) OR (projectbudgetlineitems.costitemid > 462566))
GROUP BY projectbudgets.projectid, projectbudgetyears.year, projectbudgetyears.status
Your syntax is wrong (at least according to most SQL dialects.) You can't generally say "SELECT CASE WHEN (condition) THEN (this select clause) ELSE (that select clause) END FROM (tables)"
You can only use CASE to calculate a single value.
But it looks as if the only change between your two inner SELECT clauses is whether you use 0 or the quantity in the final multiplication. And that is perfect for a CASE!
I do not guarantee this will work right off the bat, because I don't have your setup or an idea of your table layout. However, it's a step in the right direction:
SELECT
projectbudgets.projectid
, projectbudgetyears.year fiscalYear
, projectbudgetyears.status
, "sum"(
((
CASE
WHEN projectbudgetlineitems.costitemid IN (462561,462562,462563,462564,462565,462566,478030)
THEN 0
ELSE projectbudgetlineitems.quantity
END * projectbudgetlineitems.unitcost
) * (
projectbudgetlineitems.costshare * 1E-2
))) total
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN
"acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears projectbudgetyears
ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems projectbudgetlineitems
ON (projectbudgetyears.id = projectbudgetlineitems.projectbudgetyearid))
GROUP BY
projectbudgets.projectid, projectbudgetyears.year, projectbudgetyears.status
This could solve your problem if you want to sum the items for each project and year and status except for certain line items. Here, it is correct to use a "where" condition and not "case when" :
SELECT
projectbudgets.projectid,
projectbudgetyears.year,
projectbudgetyears.status,
"sum"(((projectbudgetlineitems.quantity * projectbudgetlineitems.unitcost) *
(projectbudgetlineitems.costshare * 1E-2))) total
FROM
(("acorn-prod-etl".target_acorn_prod_acorn_projectbudgets projectbudgets
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetyears
projectbudgetyears ON (projectbudgets.id = projectbudgetyears.projectbudgetid))
INNER JOIN "acorn-prod-etl".target_acorn_prod_acorn_projectbudgetlineitems
projectbudgetlineitems ON (projectbudgetyears.id =
projectbudgetlineitems.projectbudgetyearid))
WHERE projectbudgetlineitems.costitemid NOT IN
(462561,462562,462563,462564,462565,462566,478030)
GROUP BY projectbudgets.projectid, projectbudgetyears.year,
projectbudgetyears.status
;

SQL - Join Queries

Here I have two tables as student_information and exmaination_marks.
examination_marks table have 3 columns for three subjects and include their marks.
I want to select the roll_number and name of the student from the student_information table where sum of the three subject's marks in examination_marks table is less than 100.
Both table has roll_number as primary key.
Here is the query I wrote.
select
si.roll_number,
si.name
from
student_information as si
left outer join examination_marks as em on
si.roll_number = em.roll_number
where
sum(em.subject_one + em.subject_two + em.subject_three) < 100;
But I got an error saying "ERROR 1111 (HY000) at line 1: Invalid use of group function"
Can any one help me with this?
sum(em.subject_one + em.subject_two + em.subject_three)< 100
this is the problem . Try these
Where (SELECT subject_one + subject_two + subject_three FROM examination_marks WHERE em.roll_number = si.roll_number) < 100
SUM is an "aggregate function" which can only be used inside a query which has a GROUP BY clause.
To get the sum of values within the same row you need to use the + operator. If the columns are NULL-able then you'll also need to use COALESCE (or ISNULL) to prevent NULL values invalidating your entire expression.
Like so:
SELECT
si.roll_number,
si.name,
COALESCE( em.subject_one, 0 ) + COALESCE( em.subject_two, 0 ) + COALESCE( em.subject_three, 0 ) AS sum_marks
FROM
student_information AS si
LEFT OUTER JOIN examination_marks AS em ON
si.roll_number = em.roll_number
WHERE
COALESCE( em.subject_one, 0 ) + COALESCE( em.subject_two, 0 ) + COALESCE( em.subject_three, 0 ) < 100;
(If you're wondering why the COALESCE( em.subje... expression is repeated in the SELECT and WHERE clauses, that's because SQL is horribly designed by (obscene profanities) is an unnecessarily verbose language).

SQL Server Percent Difference is Greater than Value

I have the following table structures:
table c_alert:
|dynamic|symbol|price_usd|
--------------------------
|5 |BTC |13000 |
table c_current:
|symbol|price_usd|
------------------
|BTC |13600 |
I have this query:
SELECT dbo.c_alert.symbol, dbo.c_alert.price_usd AS alert_price, dbo.c_current.price_usd AS current_price, (dbo.c_current.price_usd - dbo.c_alert.price_usd) * 100.0 / dbo.c_alert.price_usd AS pct_diff, dbo.c_alert.dynamic AS pct
FROM dbo.c_alert INNER JOIN
dbo.c_current
ON dbo.c_alert.symbol = dbo.c_current.symbol AND
dbo.c_alert.dynamic > (dbo.c_current.price_usd - dbo.c_alert.price_usd) * 100.0 / dbo.c_alert.price_usd
Which returns this:
|symbol|alert_price|current_price|pct_diff|dynamic|
-----------------------------------------------
|BTC |13000 |13613.3000 |4.7 |5 |
Not very strong with financial queries...Basically I would like to know when the price difference between alert_price and current_price are equal to or greater than value in the dynamic column as a boolean. So where the difference is equal or greater than 5% show True, else False. That dynamic value (integer) could change for each row in the c_alert table. Hope someone can provide a solution to the query.
Because the same percent difference term is required in multiple places in the query, I might go with using a CTE first, which calculates this term. Then, do a straightforward query on the CTE to get the output you want.
WITH cte AS (
SELECT
t2.symbol,
t2.dynamic,
t2.price_usd AS alert_price,
t1.price_usd AS current_price,
100.0*(t1.price_usd - COALESCE(t2.price_usd, 0.0)) / t2.price_usd AS pct_diff
FROM dbo.c_current t1
LEFT JOIN dbo.c_alert t2
ON t1.symbol = t2.symbol
)
SELECT
symbol,
alert_price,
current_price,
pct_diff,
dynamic,
CASE WHEN pct_diff > dynamic THEN 'TRUE' ELSE 'FALSE' END AS result
FROM cte;
Edit:
The logic seems to be working in the demo below. If you still have issues, then edit the demo and paste the link somewhere as a comment.
Demo
Use table aliases so your query is easier to write and to read. Then just use a case:
SELECT a.symbol, a.price_usd AS alert_price,
c.price_usd AS current_price,
(c.price_usd - a.price_usd) * 100.0 / a.price_usd AS pct_diff,
a.dynamic AS pct,
(case when (a.price_usd - c.price_used) > a.dynamic
then 'true' else 'false'
end) as flag
FROM dbo.c_alert a INNER JOIN
dbo.c_current c
ON a.symbol = c.symbol AND
a.dynamic > (c.price_usd - a.price_usd) * 100.0 / a.price_usd;
SQL Server doesn't have a boolean type, so this uses a string. You can use 0 and 1 instead.

sql sum group by

I have following sql query
DECLARE #frameInt INT
SELECT TOP 1 #frameInt = gs.FrameGenerationInterval
FROM dbo.GlobalSettings gs
SELECT mti.InternalId,
b.InternalId AS BrandId,
CASE
WHEN DATEDIFF(second, mti.StartTime, mti.EndTime) / #frameInt > 0 THEN DATEDIFF(second, mti.StartTime, mti.EndTime) / #frameInt
ELSE 1
END AS ExposureAmount,
c.InternalId AS ChannelId,
c.Name AS ChannelName,
COALESCE( (p.Rating *
CASE
WHEN DATEDIFF(second, mti.StartTime, mti.EndTime) / #frameInt > 0 THEN DATEDIFF(second, mti.StartTime, mti.EndTime) / #frameInt
ELSE 1
END * CAST (17.5 AS decimal(8,2))
),CAST( 0 as decimal(8,2)) ) AS Equivalent
FROM dbo.MonitorTelevisionItems mti
LEFT JOIN dbo.Brands b ON mti.BrandId = b.InternalId
LEFT JOIN dbo.Channels c ON mti.ChannelId = c.InternalId
LEFT JOIN dbo.Programs p ON mti.ProgramId = p.InternalId
--WHERE mti.Date >= #dateFromLocal AND mti.Date <= #dateToLocal
GROUP BY mti.InternalId, mti.EndTime, mti.StartTime,
c.Name, p.Name, p.Rating,b.InternalId, c.InternalId
It gives following result
I would like it to return 1 row with sums of exposure amount and equivalent from all rows. Rest of the cells are the same apart from InternalId that I dont really need (i can remove it from query)
I am not very good at sql. Thank for help.
For the sake of posterity (and because it's cool to learn something new), here's the general solution to your problem (instead of a copy-and-paste ready solution for your specific case):
SELECT group_field1, group_field2, ...,
SUM(sum_field1), SUM(sum_field2), ...
FROM (...your original SQL...) AS someArbitraryAlias
GROUP BY group_field1, group_field2, ...
In your specific case, the group fields would be BrandId, ChannelId and ChannelName; the sum fields would be ExposureAmount and Equivalent.
Note: To ease readability (since your original SQL is quite complex), you can use a common table expression:
WITH someArbitraryAlias AS (
...your original SQL...
)
SELECT group_field1, group_field2, ...,
SUM(sum_field1), SUM(sum_field2), ...
FROM someArbitraryAlias
GROUP BY group_field1, group_field2, ...
Note that, when using common table expressions, the immediately preceding statement must be terminated with a semicolon.

Why colums in SELECT not belongs to SELECT

I have this select, but does not work.
select
a.code1,
a.data1,
a.stval,
(select sum(col1+col2+col3) from tad ) as sum1,
(select sum(col7+col8+col9) from tbac) as sum2,
CASE
WHEN (sum1+sum2) > 100 THEN (a.stval * sum1)
WHEN (sum1+sum2( <= 100 THEN (a.stval * sum2)
END as newdat1
from arti as a
Where is the error? why (sum1+sum2) its error?
Thanks
(sum1 + sum2) is an error because these identifiers are not defined in the scope where you are trying to use them. In an SQL select list, you cannot use symbols declared in the same select list, irrespective of their position on the list. Use a subquery if you need to access sum1 and sum2.
The specific reason is that SQL is a descriptive language that does not guarantee the order of evaluation of expressions. This is true in the select clause. This is true in the where clause. It is true in the from clause. SQL describes what the results look like. It does not prescribe the specific actions.
As a result, SQL does not allow identifiers defined in the select to be used in the same select clause (nor in the where clause at the same level). The expressions can be processed in any order.
The normal solution in your case is to use a subquery or a CTE. In your case, though, the subqueries are independent of the outer query (as written), so I would move them to the from clause:
select a.code1, a.data1, a.stval, x1.sum1, x2.sum2,
(CASE WHEN x1.sum1 + x2.sum2 > 100 THEN a.stval * x1.sum1
WHEN x1.sum1 + x2.sum2 <= 100 THEN a.stval * x2.sum2
END) as newdat1
from arti a cross join
(select sum(col1+col2+col3) as sum1 from tad ) x1 cross join
(select sum(col7+col8+col9) as sum2 from tbac) x2;
EDIT:
You can use a subquery or CTE. But there is an approach that builds on the above:
select a.code1, a.data1, a.stval, x1.sum1, x2.sum2,
(CASE WHEN x1.sum1 + x2.sum2 > 100 THEN a.stval * x1.sum1
WHEN x1.sum1 + x2.sum2 <= 100 THEN a.stval * x2.sum2
END) as newdat1
from arti a join
(select ascon, sum(col1+col2+col3) as sum1
from tad
group by ascon
) x1
on x1.ascon = arti.code1 cross join
(select sum(col7+col8+col9) as sum2 from tbac) x2;