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;
Related
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).
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.
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!
I am trying to write a SQL statement which reuses the subquery of the With clause multiple times in Oracle.
With mySubQ as (
...
)
Select Something
From SomeTable,
(
Select *
From mySubQ
where mySubQ.Something >= 0
) newSubQ
where mySubQ.Something = SomeTable.Something
This gives me error - ORA-32034 unsupported use of WITH clause
What am I missing?
You need to join with mySubQ, not just define it.
WITH mySubQ AS (...)
SELECT Something
FROM SomeTable
JOIN mySubQ ON mySubQ.Something = SomeTable.Something
WHERE mySubQ.Something >= 0
If you put the query of mySubQ in a subquery, you can't reference mySubQ in the WHERE clause of the main query. Each level of query can only access tables in its own FROM and JOIN clauses, not those of subqueries.
Here is the error: where mySubQ.Something = SomeTable.Something.
The bottom query selects from SomeTable and from the subquery with alias newSubQ,
so mySubQ.Something is not known in this context.
If something is a real column name, not only a "placeholder in the pseudocode", then there is also another error here: Select Something - the column is ambiguous, because both sometable and the subquery have this column.
Try this query:
With mySubQ as (
SELECT * FROM sometable
)
Select newSubQ.Something
From SomeTable,
(
Select *
From mySubQ
where mySubQ.Something >= 0
) newSubQ
where newSubQ.Something = SomeTable.Something
;
Demo --> http://www.sqlfiddle.com/#!4/88855/12
This demo contains also another example of using WITH clause:
WITH mySubQ AS (
SELECT *
FROM sometable
),
mySubQ_1 AS (
SELECT *
FROM mySubQ
WHERE somethingelse = 1
),
mySubQ_2 AS (
SELECT *
FROM mySubQ
WHERE something between 2 AND 5
)
SELECT *
FROM sometable s, mySubQ_1 m1,
(
SELECT * FROM mySubQ_2
WHERE something < 10
) m2
WHERE s.something = m1.something
AND m1.somethingelse = m2.somethingelse
Is it possible to use COUNT in place of EXISTS?
I have following query:
SELECT *
FROM Goals G
WHERE EXISTS (SELECT NULL FROM tfv_home_last6(G.Date, G.Home) WHERE GameNumber <= 6 AND
HomeGoals >= 3)
Instead of returning the row if at least one row exists in the subquery, I'd like to specify a number of rows that need to be returned in the subquery, something like
SELECT *
FROM Goals G
WHERE ROWCOUNT(*) >= 2 (SELECT NULL FROM tfv_home_last6(G.Date, G.Home) WHERE GameNumber <= 6 AND
HomeGoals >= 3)
I'm not sure how to go about it?
I'm using SQL Server 2012.
You can do the subquery pretty much just like you describe:
SELECT *
FROM Goals G
WHERE (SELECT count(*)
FROM tfv_home_last6(G.Date, G.Home)
WHERE GameNumber <= 6 AND HomeGoals >= 3
) > 0;
However, this requires calculating the entire count. The exists form is more efficient, because it stops at the first matching record.
In SQL Server 2012, you could also use `cross apply:
SELECT *
FROM Goals G cross apply
(select count(*) as cnt
FROM tfv_home_last6(G.Date, G.Home)
WHERE GameNumber <= 6 AND HomeGoals >= 3
) a
WHERE a.cnt > 0;
I do not know which would have better performance, the correlated subquery in the where clause or the
cross apply version.