SQL Server : execution plan explanation - sql

I have this execution plan, but I have just a slight guess what's happening here. I think the plan divide my query to 2 interval, which are inner joined, but I have no clue what is the upper row means starting with the Merge interval.
My plan on Brentozar
My query is:
select Price, ID
from product
where price <> 800
ID is my primary key, Price has index
Thank you in advance

This apparatus is used for "dynamic seeks" in SQL Server. Often you will see this due to mismatched datatypes.
In your case the literal 800 is auto parameterised to an int parameter and the plan later has a CONVERT_IMPLICIT(float(53),[#1],0) to convert it to the datatype of the price column. I replace this with 800e0 below (one way of declaring that value as a float literal)
(sidenote: price should not be float - you should use a precise datatype such as decimal)
Node 6 outputs a single row with no columns. The compute scalar in
Node 5 adds three columns to the row with values (NULL, 800e0, 10)
Node 8 outputs a single row with no columns. The compute scalar in
Node 7 adds three columns to the row with values (800e0, NULL, 6)
Node 4 is a concatenation operator that UNION ALLs the above two rows together. The resultant columns are aliased as (Expr1009, Expr1010, Expr1011) - these correspond to (startOfRange, endOfRange, Flags) - NULL here means "unbounded"
Nodes 3,2 and 1 are concerned with ordering the ranges so that overlapping ones can be collapsed down and have no effect in this case.
Node 9 is an index seek that is executed twice (for the two rows on the outside of the join). This has a seek predicate of Price > Expr1009 AND Price < Expr1010 - i.e. Price > startOfRange AND Price < endOfRange. So it is called for range (NULL, 800) and range (800, NULL)
So the net effect of all this is that the <> 800 predicate gets converted to two index seeks. One on < 800 and the other on >800

Related

Query smallest number of rows to match a given value threshold

I would like to create a query that operates similar to a cash register. Imagine a cash register full of coins of different sizes. I would like to retrieve a total value of coins in the fewest number of coins possible.
Given this table:
id
value
1
100
2
100
3
500
4
500
5
1000
How would I query for a list of rows that:
has a total value of AT LEAST a given threshold
with the minimum excess value (value above the threshod)
in the fewest possible rows
For example, if my threshold is 1050, this would be the expected result:
id
value
1
100
5
1000
I'm working with postgres and elixir/ecto. If it can be done in a single query great, if it requires a sequence of multiple queries no problem.
I had a go at this myself, using answers from previous questions:
Using ABS() to order by the closest value to the threshold
Select rows until a sum reduction of a single column reaches a threshold
Based on #TheImpaler's comment above, this prioritises minimum number of rows over minimum excess. It's not 100% what I was looking for, so open to improvements if anyone can, but if not I think this is going to be good enough:
-- outer query selects all rows underneath the threshold
-- inner subquery adds a running total column
-- window function orders by the difference between value and threshold
SELECT
*
FROM (
SELECT
i.*,
SUM(i.value) OVER (
ORDER BY
ABS(i.value - $THRESHOLD),
i.id
) AS total
FROM
inputs i
) t
WHERE
t.total - t.value < $THRESHOLD;

How to calculate the ratio of this column with 2 rows

I am very new to SQL and am having difficulty figuring out hot to divide row1 (101) by row2 (576).
COUNT
101
576
I want the output to be a single value expressed to 2 decimal places.
Any tips?
Thanks for the help
For two rows, it's easy.
If you have a big input table, and you want to divide the first row by the second, the third row by the fourth, etc, then you need an ordering column to save yourself.
So, with a two-row table (remember, tables are never ordered), you just rely on the fact that you divide the smaller number by the bigger number.
Here goes:
WITH
-- your input ...
input(counter) AS ( -- count is reserved word, use another name ...
SELECT 101
UNION ALL SELECT 576
)
-- cheat and just divide the smaller by the bigger
-- as "#Gordon Linoff" suggests
-- force a float division by adding a non-integer operand
-- and hard-cast it to DECIMAL(5,2)
SELECT
CAST(
MIN(counter) * 1.00 / MAX(counter)
AS DECIMAL(5,2)
) AS result
FROM input;
-- out result
-- out ----------
-- out 0.18
If, however, you have many rows, and you always need to divide the first row by the second, the third row by the fourth, that is, each odd row in the order by the next even row in the order, then you need an ordering column.
Is your problem just what you suggested, or is there more to it?
There is no such thing as row "1" or "2" in a table. Tables represent unordered sets, so without a column specifying the ordering, there is no first or second row.
You can use aggregation to divide by min by the max:
select min(count) * 1.0 / max(count)
from t;
Note the * 1.0. Postgres does integer division, so you want to convert to something with a decimal point.

Equivalent of Python's Map operator in PostgreSQL

I have a table in PostgreSQL DB like this.
ID, Name, scores.
10, abc,{23,19,34}
11, def, {2333,233,24}
12, ghi, {321,34}
13,hio,{}
scores in the above data model is an array or list of numbers.
Now we have to find all students who has any single score which is 19 when divided by 10. How can I achieve this?
I tried this, but it doesn't work.
SELECT * FROM students where 19 = ANY(scores)/10
Some thing like this works. But we need a better solution(using an inverted index probably) as the rows are in the order of millions.
SELECT * FROM students where 190 <= ANY(scores) < 200
In your data example there is no record that meet your condition of some value that when divided by 10 is =19. But i understand that you are sure about your condition that single number from array when divided by 10 should be equal to 19. Not sum of all or something?
First do you have gin index on score column?
Second - really single numbers in your score array will be bigger then int limit? If not bigint will just slow your queries.
Consider bigint issue and if you have to have it then, else remove ::bigint from query below
SELECT * FROM students where
scores&&array[190,191,192,193,194,195,196,197,198,199]::bigint
It is ugly but probably faster then any tries of extract all number from array first then dividing them by 10 and then comparing to 19.
If you only search score for numbers that are equal 19 after dividing by 10, just use the method of Abelisto but it will be a killer during inserting as saving function index for milions of rows and long arrays will be slow.

Mdx - Flag -Actual

I have two dimensions DimFlag and DimPNL and a fact table FactAmount. I am looking to:
When pnl is stat(Is Stat=1) : sum (Actual x FlagId)
For pnl I multiply the amounts by field FlagId basically if it will be so 0 0 X = 0 ...
DimFlag
FlagId FlagLabel
-----------------
1 NotClosed
0 IsClosed
DimPNL
PNLId PNLName Is Stat
1 a 1
2 test 1
3 test2 0
FactAmount
id PNLId FlagId Actual
1 1 1 100
2 2 1 10
3 3 0 120
I tried the following MDX but it didn't work, any idea please ?
Scope (
[Dim PNL].[PNL].members,[Measures].members
);
this = iif([Dim PNL].[PNL].CurrentMember.Properties("Is Stat") =1
,
aggregate([Dim PNL].[PNL].currentmember,[Measures].currentmember)* iif([Dim Flag].[Flag Label].[Flag Label].currentmember = 0, 0, 1),
aggregate([Dim PNL].[PNL].currentmember,[Measures].currentmember)
);
While this type of calculation can be done in MDX, the MDX can get complex and performs bad. I would suggest to explicitly do the calculation e. g. in the DSV or a view on the fact table that you then use instead of the fact table directly in the DSV. The result of the calculation would then be another column on which you can base a standard measure.
To do it in the DSV, assuming you use a relational table as the base for the fact table, add a named calculation to it, define the column name however you like, and use the expression Actual * FlagID. For the other calculation, you may need a subselect, i. e. the expression would be Actual * case when pnlId in(1,2) then 1 else 0 end. You can use any SQL that works as a column expression in the select list as the expression in for a named calculation.
Implementing the same in a view on FactAmount, you could implement the second expression better, as then you could join table DimPNL in the view definition and thus use column IsStat in the calculation. Then you would replace table FactAmout by the view, which has the two additional measure columns.
In either case, just define two measures on the two new columns in the cube, and you are done.
As a rule, calculations that are done on record level in the fact table before any aggregation should be done at data loading time, i. e. as described above.

SQL Server SQL Select: How do I select rows where sum of a column is within a specified multiple?

I have a process that needs to select rows from a Table (queued items) each row has a quantity column and I need to select rows where the quantities add to a specific multiple. The mulitple is the order of between around 4, 8, 10 (but could in theory be any multiple. (odd or even)
Any suggestions on how to select rows where the sum of a field is of a specified multiple?
My first thought would be to use some kind of MOD function which I believe in SQL server is the % sign. So the criteria would be something like this
WHERE MyField % 4 = 0 OR MyField % 8 = 0
It might not be that fast so another way might be to make a temp table containing say 100 values of the X times table (where X is the multiple you are looking for) and join on that