Reference a projected/selected column? - sql

I project a column in my select statement. ("project" in the relational algebra sense.) With the goal of reducing code duplication, is there a way to reference that projected column in my where clause? Or is there a better way to do that?
Example:
select
(A.Column + A.Column2) * 8 'Column'
from A
where
(A.Column + A.Column2) * 8 < 1000
Basically, what I'm asking, if we think of columns as being "namespaced" by table (where A is a namespace and A.Column is the Column in the A namespace), is: is there a way to refer to the namespace for the ephemeral table we're currently selecting in the where clause of that table itself?

Another way is to use cte, common table expression.
with cte as(
select (A.Column + A.Column2) * 8 as [Column] from A
)
Select * from cte
Where [Column] < 1000

You can do it;
select * from
(
select (A.Column + A.Column2) * 8 as Col from A
) tmp
where Col<1000

Related

Using created column in select statement twice

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!

get number of rows select statement will fetch (without real fetching)

Lets say I have many sql statements like this one:
select *
from [A]
where a in (
select a
from [B]
where b = 'c'
)
order by d;
Since my database is huge, I just need to determine how many rows this query will fetch. Of course I can really fetch all rows and count it but my intention is to avoid fetching since that would be a big overhead.
I have tried to extend query as follows:
select count (*)
from (
select *
from [A]
where a in (
select a
from [B]
where b = 'c'
)
order by d
) as table;
That works fine for some tables but for some (like this one in example) SQL server throws this:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
Consider that I'm not allowed to change any original query, I can just extend it...
Any idea?
Thanks.
EDIT: I'm pretty sure there is some solution related to ##ROWCOUNT field, but not sure how to use it...
Just remove the order by in the subquery. It doesn't affect the number of rows:
select count(*)
from (select *
from [A]
where a in (select a from [B] where b = 'c')
) as table;
Actually, this is better written as:
select count(*)
from [A]
where a in (select a from [B] where b = 'c')
That is, just replace the select * with select count(*).
Finally, if you have to keep the queries the same, then use top 100 percent:
select count(*)
from (select top 100 percent *
from [A]
where a in (select a from [B] where b = 'c')
order by d
) as table;
This does require changing the original queries, but in a way that does not affect what they output and does allow them to be used as ctes/subqueries.
You are allowed to use order by in subqueries when you also use top.
EDIT:
If you are using dynamic SQL, you might have to do something like:
#sql = 'select count(*) from (' +
(case when #sql not like 'SELECT TOP %'
then stuff(#sql, 1, 7, 'SELECT top 100 percent')
else #sql
end) +
+ ')';
The logic could be a bit more complicated if your SQL is not well formatted.

Reuse subquery result in WHERE-Clause for INSERT

i am using Microsoft SQL Server 2008
i would like to save the result of a subquery to reuse it in a following subquery.
Is this possible?
What is best practice to do this? (I am very new to SQL)
My query looks like:
INSERT INTO [dbo].[TestTable]
(
[a]
,[b]
)
SELECT
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
)
,(
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = MAT_WS_ID
--(
--SELECT TOP 1 MAT_WS_ID
--FROM #TempTableX AS X_ALIAS
--WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
--)
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
My question is:
Is this correct what i did.
I replaced the second SELECT Statement in the WHERE-Clause for [b] (which is commented out and exactly the same as for [a]), with the result of the first SELECT Statement of [a] (=MAT_WS_ID).
It seems to give the right results.
But i dont understand why!
I mean MAT_WS_ID is part of both temporary tables X_ALIAS and Y_ALIAS.
So in the SELECT statement for [b], in the scope of the [b]-select-query, MAT_WS_ID could only be known from the Y_ALIAS table. (Or am i wrong, i am more a C++, maybe the scope things in SQL and C++ are totally different)
I just wannt to know what is the best way in SQL Server to reuse an scalar select result.
Or should i just dont care and copy the select for every column and the sql server optimizes it by its own?
One approach would be outer apply:
SELECT mat.MAT_WS_ID
, (
SELECT TOP 1 MAT_WS_NAME
FROM #TempTableY AS Y_ALIAS
WHERE Y_ALIAS.MAT_WS_ID = mat.MAT_WS_ID
)
FROM [dbo].[LASERTECHNO] AS OUTERBASETABLE
OUTER APPLY
(
SELECT TOP 1 MAT_WS_ID
FROM #TempTableX AS X_ALIAS
WHERE OUTERBASETABLE.LT_ALL_MATERIAL = X_ALIAS.MAT_RM_NAME
) as mat
You could rank rows in #TempTableX and #TempTableY partitioning them by MAT_RM_NAME in the former and by MAT_WS_ID in the latter, then use normal joins with filtering by rownum = 1 in both tables (rownum being the column containing the ranking numbers in each of the two tables):
WITH x_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_RM_NAME ORDER BY (SELECT 1))
FROM #TempTableX
),
y_ranked AS (
SELECT
*,
rownum = ROW_NUMBER() OVER (PARTITION BY MAT_WS_ID ORDER BY (SELECT 1))
FROM #TempTableY
)
INSERT INTO dbo.TestTable (a, b)
SELECT
x.MAT_WS_ID,
y.MAT_WS_NAME
FROM dbo.LASERTECHNO t
LEFT JOIN x_ranked x ON t.LT_ALL_MATERIAL = x.MAT_RM_NAME AND x.rownum = 1
LEFT JOIN y_ranked y ON x.MAT_WS_ID = y.MAT_WS_ID AND y.rownum = 1
;
The ORDER BY (SELECT 1) bit is a trick to specify an indeterminate ordering, which, accordingly, would result in indeterminate rownum = 1 rows picked by the query. That is to more or less duplicate your TOP 1 without an explicit order, but I would recommend you to specify a more sensible ORDER BY clause to make the results more predictable.

SQL SUM question

Hi I have a question about SUM in sql,
I have a query that looks like this
SELECT
SUM ( table_one.field + table_two.field ) as total_field
SUM ( total_field + table_one.anotherfield )
FROM
table_one
JOIN
table_two ON table_one.id = table_two.id
WHERE
table_one = 1
But this doesn't work ( dont mind possible typing errors in JOIN statement, only the second SUM is the probly the query works perfecly without that SUM)
Is there another way to do it, as I need the total_field within my application. I can ofcource add those numbers within the application but I prefer to do it in sql.
You cannot use the column alias in an aggregate to reference the value, just SUM again;
SELECT
SUM ( table_one.field + table_two.field ) as total_field, --your missing a , also
SUM ( table_one.field + table_two.field + table_one.anotherfield )
FROM
table_one
JOIN
table_two ON table_one.id = table_two.id
WHERE
table_one = 1
SUM is an aggregate function. This means you can aggregate data from a field over several tuples and sum it up into a single tuple.
What you want to do is this:
SELECT
table_one.field + table_two.field,
table_one.field + table_two.field + table_one.anotherfield
or maybe this:
SELECT
SUM(table_one.field) + SUM(table_two.field),
SUM(table_one.field) + SUM(table_two.field) + SUM(table_one.anotherfield)
Try replacing "total_field" with "table_one.field + table_two.field" in second SUM().
The name "total_field" is an alias and as such cannot be used in an aggregate functions
The easiest and quickest way is to simply replace the code for total_field in the second calculation.
SELECT
SUM ( ISNULL(table_one.field,0) + ISNULL(table_two.field,0) ) as total_field
SUM ( ISNULL(table_one.field,0) + ISNULL(table_two.field,0) + IsNUll(table_one.anotherfield,0) )
from
table_one
As your code doesn't cater for a null value in the fields you may get warnings when sum the values. I would suggest using IsNull as above and if there is a null value just treat it as 0.
You could use a subquery like this:
SELECT
total_field,
total_field + sum_anotherfield
FROM (
SELECT
SUM(table_one.field + table_two.field) AS total_field,
SUM(table_one.anotherfield) AS sum_anotherfield
FROM
table_one
JOIN
table_two ON table_one.id = table_two.id
WHERE
table_one.somefield = 1
) x

PostgreSQL Views: Referencing one calculated field in another calculated field

I have the same question as #1895500, but with PostgreSQL not MySQL.
How can I define a view that has a calculated field, for example:
(mytable.col1 * 2) AS times_two
... and create another calculated field that's based on the first one:
(times_two * 2) AS times_four
...?
Depending on how heavy the formla is, you could use a subquery:
select inner.*, times_two * 2 from
(select mycol * 2 as times_two from table) sub
Or rewrite the computation:
select mycol * 2, mycol * 2 * 2 from table
Use this statement
CREATE VIEW view_name as SELECT column_name*2 as new_col1 , column_name*4 as new_col2 from table_name ;
select * from view_name ;
If you want use this view column values. use following things
create view new_viwe as select new_col1*2 as final_column from view_name ;
select * from new_view ;