I want to use the result from subquery as the column name of another query since the data changes column all the time and the subquery will decide which column the current forcast data stored. My example:
select item,
item_type
...
forcast_0 * 0.9 as finalforcast
forcast_0 * 0.8 as newforcast
from sales_data.
but the forcast_0 column is the result (fore_column_name) of the subquery, the result may change to forcast_1 or forcast2
select
fore_column_name
from forecast_history
where ...
Also, the forcast column will be used multiple times in the first query. how could I implement this?
Use your sub query as an inline table. Something like....
select item,
item_type,
..
decode(fore_column_name, 'foo', 1, 2) * 0.9 as finalforcast,
decode(fore_column_name, 'foo', 1, 2) * 0.8 as newforcast
from sales_data,
(
select fore_column_name
from forecast_history
where ...
) inlineTable
I'm assuming here that the value from the sub-query will be the same for each row - so a quick cross-join will suffice. If the value will vary depending on the values in each row of the sales_data table, then some other type of join would be more appropriate.
Quick link to decode - in case you aren't familiar with it.
Related
I have a table with "Number", "Name" and "Result" Column. Result is a 2D text Array and I need to create a Column with the name "Average" that sum all first values of Result Array and divide by 2, can somebody help me Pls, I must use the create function for this. Its look like this:
Table1
Number
Name
Result
Average
01
Kevin
{{2.0,10},{3.0,50}}
2.5
02
Max
{{1.0,10},{4.0,30},{5.0,20}}
5.0
Average = ((2.0+3.0)/2) = 2.5
= ((1.0+4.0+5.0)/2) = 5.0
First of all: You should always avoid storing arrays in the table (or generate them in a subquery if not extremely necessary). Normalize it, it makes life much easier in nearly every single use case.
Second: You should avoid more-dimensional arrays. The are very hard to handle. See Unnest array by one level
However, in your special case you could do something like this:
demo:db<>fiddle
SELECT
number,
name,
SUM(value) FILTER (WHERE idx % 2 = 1) / 2 -- 2
FROM mytable,
unnest(avg_result) WITH ORDINALITY as elements(value, idx) -- 1
GROUP BY number, name
unnest() expands the array elements into one element per record. But this is not an one-level expand: It expand ALL elements in depth. To keep track of your elements, you could add an index using WITH ORDINALITY.
Because you have nested two-elemented arrays, the unnested data can be used as follows: You want to sum all first of two elements, which is every second (the odd ones) element. Using the FILTER clause in the aggregation helps you to aggregate only exact these elements.
However: If that's was a result of a subquery, you should think about doing the operation BEFORE array aggregation (if this is really necessary). This makes things easier.
Assumptions:
number column is Primary key.
result column is text or varchar type
Here are the steps for your requirements:
Add the column in your table using following query (you can skip this step if column is already added)
alter table table1 add column average decimal;
Update the calculated value by using below query:
update table1 t1
set average = t2.value_
from
(
select
number,
sum(t::decimal)/2 as value_
from table1
cross join lateral unnest((result::text[][])[1:999][1]) as t
group by 1
) t2
where t1.number=t2.number
Explanation: Here unnest((result::text[][])[1:999][1]) will return the first value of each child array (considering you can have up to 999 child arrays in your 2D array. You can increase or decrease it as per your requirement)
DEMO
Now you can create your function as per your requirement with above query.
I am grouping by records base on one column. What I want to know if all of these records has got the same value in another column.
So far I achieve this with the following logic, which I believe is too complex:
select number,
if(flagSum = 0 OR flagSum = groupedrecords, "AllSame", "SomeDifferent") as AllIndicatorEqual
from
(select number,
sum(if(flag = 'Y', 1, 0)) as flagSum,
count(*) as groupedrecords
from table
where number = '1234'
group by number
)tab
So basically I group by number, and check if all records grouped has got the same flag value.
Is there a more efficient way to calculate this?
You could probably skip a subquery by using a distinct count :
select
number,
if(count(distinct flag) = 1, "AllSame", "SomeDifferent") as AllIndicatorEqual
from table
group by number;
http://sqlfiddle.com/#!9/20e024/6
I can do this in SQL Server:
SELECT 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
(select sum(empid) from HR.employees) STOCK
but in Access the same query show me the next error:
Query input must contain at least one table or query
So which could be the best form to emulate this? Make a query with any other table looks dirty for me.
EDIT 1:, HR.employees It may no have data, but i want show constants ('HERRAMIENTA ELÉCTRICA',''0') and 0 in the third column, maybe using isnull and this is not the problem here.
Why not to select directly:
select 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
IIF(ISNULL(sum(empid)), 0, sum(empid)) AS STOCK
from HR.employees
This simply doesn't work in Access. You need a FROM clause.
So you need to have a dummy table with one record, even if you don't use a single field from that table.
SELECT 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
(select sum(empid) from HR.employees) STOCK
FROM Dummy_Table
Using this example as empty table:
with employ as
(select 2 as col from dual
minus
select 2 as col from dual)
The query is this one:
select 'HERRAM' as tipo,
0 as deprec,
coalesce(sum(col), 0) as STOCK
from employ;
coalesce(x, value) sets the column to value when X is null
In Access, you can use a system table, and Val and Nz for the zero value:
SELECT TOP 1
'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
Val(Nz((select sum(empid) from HR.employees), 0)) AS STOCK
FROM
MSysObjects
I have several columns in a SQL table, and I would like to compute the result for each row in the table. My data looks something like this:
data
name value adjustor1 adjustor2
Comp1 20 0.05 0.08
Comp2 80 -0.07 0.065
The formula for the adjusted value for each row is:
adjusted_value = value*(1 + adjustor1)*(1 + adjustor2)*(100/sum(value))
So the adjusted output should be:
data
name adjusted_value
Comp1 22.25
Comp2 77.75
The original values sum to 100, and the adjusted values should also sum to 100. I've tried things such as:
SELECT adjusted*(100/sum(adjusted))
FROM (
SELECT value*(1+adjustor1)*(1+adjustor2) as adjusted
FROM data
) as result
which gives me the error: ERROR: column "result.adjusted" must appear in the GROUP BY clause or be used in an aggregate function
Although if I just do:
SELECT sum(adjusted)
FROM (
SELECT value*(1+adjustor1)*(1+adjustor2) as adjusted
FROM data
) as result
OR
SELECT adjusted
FROM (
SELECT value*(1+adjustor1)*(1+adjustor2) as adjusted
FROM data
) as result
I can get either the sum OR the adjusted value, but not both.
Column name value is not a good choice, it is a reserved word. I changed it to val instead.
This is the query you need:
WITH data(name,val,adjustor1,adjustor2) AS (
VALUES
('Comp1'::text,20,0.05,0.08),
('Comp2',80,-0.07,0.065)
)
SELECT name,val,adjustor1,adjustor2,
CAST(val*(1+adjustor1)*(1+adjustor2)*(100/sum(
val*(1+adjustor1)*(1+adjustor2)
) OVER ()) AS numeric(10,3)) adjusted_value
FROM data;
I must admit, it is a bit clumsy, sub-query makes it easier to understand (SQL Fiddle):
WITH data(name,val,adjustor1,adjustor2) AS (
VALUES
('Comp1'::text,20,0.05,0.08),
('Comp2',80,-0.07,0.065)
)
SELECT name, CAST(adj*(100/sum(adj) OVER ()) AS numeric(8,3)) adjusted_value
FROM (
SELECT name,val,adjustor1,adjustor2,
val*(1+adjustor1)*(1+adjustor2) adj
FROM data) s;
Some notes:
Original sum(adj) is replaced with sum(adj) OVER (), which is a syntax for window functions.
I also added [CAST()][3] in order to round up the values.
you can get the SUM in a subquery and then you can do CROSS JOIN to achieve what you want
SELECT name,
value*(1+adjustor1)*(1+adjustor2)*(100/T.adjSum) as adjusted_value
FROM data
CROSS JOIN
(SELECT SUM(value*(1+adjustor1)*(1+adjustor2)) as adjSum
FROM data) T
I have table with 3 columns A B C.
I want to select * from this table, but ordered by a specific ordering of column A.
In other words, lets' say column A contains "stack", "over", "flow".
I want to select * from this table, and order by column A in this specific ordering: "stack", "flow", "over" - which is neither ascending nor descending.
Is it possible?
You can use a CASE statement in the ORDER BY clause. For example ...
SELECT *
FROM Table
ORDER BY
CASE A
WHEN 'stack' THEN 1
WHEN 'over' THEN 2
WHEN 'flow' THEN 3
ELSE NULL
END
Check out Defining a Custom Sort Order for more details.
A couple of solutions:
Create another table with your sort order, join on Column A to the new table (which would be something like TERM as STRING, SORTORDER as INT). Because things always change, this avoids hard coding anything and is the solution I would recommend for real world use.
If you don't want the flexibility of adding new terms and orders, just use a CASE statement to transform each term into an number:
CASE A WHEN 'stack' THEN 1 WHEN 'over' THEN 2 WHEN 'flow' THEN 3 END
and use it in your ORDER BY.
If you have alot of elements with custom ordering, you could add those elements to a table and give them a value. Join with the table and each column can have a custom order value.
select
main.a,
main.b,
main.c
from dbo.tblMain main
left join tblOrder rank on rank.a = main.a
order by rank.OrderValue
If you have only 3 elements as suggested in your question, you could use a case in the order by...
select
*
from dbo.tblMain
order by case
when a='stack' then 1
when a='flow' then 2
when a='over' then 3
else 4
end