SQL Server query problem. example is in excel sheet picture - sql-server

Please see the following pic and i want to convert this formula in SQL Server.
in excel sheet
M N
15 1 0
16 3 1
17 5 2
18 8 4
19 9 4
N= IF(M16-M15<=1,N15,M16-M15-1+N15
Please see the screenshot for reference:

As per your tags, this can be done with LAG and then doing a running total.
For each row, first calculate the difference in M from the previous row (using LAG) - I call this Dif_Last_M. This mirrors the 'M24-M23' part of your formula.
If Dif_Last_M is <= 1, add 0 to the running total (effectively making the running total the same as for the previous row)
Else if Dif_Last_M is > 1, add (Dif_Last_M minus 1) to the running total
Here is the code assuming your source table is called #Temp and has an ID (sorting value)
WITH M_info AS
(SELECT ID, M, (M - LAG(M, 1) OVER (ORDER BY ID)) AS Dif_Last_M
FROM #Temp
)
SELECT ID,
M,
SUM(CASE WHEN Dif_Last_M > 1 THEN Dif_Last_M - 1 ELSE 0 END) OVER (ORDER BY ID) AS N
FROM M_info;
And here are the results
ID M N
1 1 0
2 3 1
3 5 2
4 8 4
5 9 4
6 12 6
7 13 6
Here is a db<>fiddle with the above. It also includes additional queries showing
The result from the CTE
The values used in the running total
Note that while it possible to do this with recursive CTEs, they tend to have performance problems (they are loops, fundamentally). Soit is better (performance-wise) to avoid recursive CTEs if possible.

Related

Transpose rows 1 and 0 's into different rows in Snowflake

I'm trying to load a file and transpose the row into different rows.
Days Column have 11010011 and need to transpose into vertical format.
Below is the sample input
I'm trying to get the expected output like below
Can you please help me on this in Snowflake? Appreciate your help
Replace '1' with '1,' and '0' with '0,'. Trim the trailing comma. You can then use split to table to turn that into rows:
with SOURCE_DATA as
(
select COLUMN1::int as FACTORY
,COLUMN2::int as YEAR
,COLUMN3::string as DAYS
from (values
(01,2021,'01010100100101010001'),
(99,2021,'00100111010101011010')
)
)
select FACTORY, YEAR, SEQ as SOURCE_ROW, INDEX as POSITION_IN_STRING, VALUE as WORKING_DAY
from SOURCE_DATA, table(split_to_table(trim(replace(replace(DAYS,'1','1,'),'0','0,'),','),',')) D
;
Abbreviated output:
FACTORY
YEAR
SOURCE_ROW
POSITION_IN_STRING
WORKING_DAY
1
2021
1
1
0
1
2021
1
2
1
1
2021
1
3
0
1
2021
1
4
1
1
2021
1
5
0
The split() table function gives you some metadata columns with information on the split. You can change the sample to select * to see them and maybe they're useful in some way for your requirements.

SQL add to select the sum of equal values

SELECT
hg.referencia AS Referencia,
hg.toleInf AS Min,
hg.toleSup AS Max,
ROUND(CAST((hrg.x1+hrg.x2+hrg.x3+hrg.x4)/4 AS FLOAT),2) AS X,
COUNT(hg.Referencia) AS NumGraficos
FROM hRegGeometrias hrg
JOIN hGeometria hg
ON hrg.idGeometria = hg.idGeom
WHERE hrg.idMatriz = 2
GROUP BY hg.referencia, hg.toleInf, hg.toleSup, hrg.x1, hrg.x2, hrg.x3, hrg.x4, hrg.idRegisto
ORDER BY Referencia, IdRegisto ASC
which returns this
what i expect is that it sums the column Referencia but only distinct value, like for example, the sum should be 2 because there's only
'M130342'
'M130344'
So in the column NumGraficos, i would expect the value to be 2.
How to achieve this?
Referencia Min Max X NumGraficos
M130342 2 7 9,81 1
M130342 2 7 9,8 1
M130342 2 7 3,25 1
M130342 2 7 1,75 1
M130342 2 7 3,13 1
M130344 1 7 2 1
M130344 1 7 4,75 1
M130344 1 7 3,25 1
EDIT
It's probably impossible to get the result I expect since this database relations are messed up. I will try a different approach by returning some values separatedly

T-SQL to sum total value instead of rejoining table multiple times

I've looked for an example question like this, I ask for grace if it's been answered (I thought it would have been but have a hard time finding meaningful results with the terms I searched.)
I work at a manufacturing plant where at ever manufacturing operation a part is issued a new serial number. The database table I have to work with has the serial number recorded in the Container field and the previous serial number the part had recorded in the From_Container field.
I'm trying to SUM the Extended_Cost column on parts we've had to re-do operations on.
Here's a sample of data from tbl_Container:
Container From_Container Extended_Cost Part_Key Operation
10 9 10 PN_100 60
9 8 10 PN_100 50
8 7 10 PN_100 40
7 6 10 PN_100 30
6 5 10 PN_100 20
5 4 10 PN_100 50
4 3 10 PN_100 40
3 2 10 PN_100 30
2 1 10 PN_100 20
1 100 10 PN_100 10
In this example the SUM I would expect returned is 40, because operations 20, 30, 40 and 50 were all re-done and cost $10 each.
So far I've been able to do this by rejoining the table to itself 10 times using aliases in the following fashion:
LEFT OUTER JOIN tbl_Container AS FCP_1
ON tbl_Container.From_Container = FCP_1.Container
AND FCP_1.Operation <= tbl_Container.Operation
AND tbl_Container.Part_Key = FCP_1.Part_Key
And then using SUM to add the Extended_Cost fields together. However, I'm violating the DRY principle and there has got to be a better way.
Thank you in advance for your help,
Me
You can try this query.
;WITH CTE AS
(
SELECT TOP 1 *, I = 0 FROM tbl_Container C ORDER BY Container
UNION ALL
SELECT T.*, I = I + 1 FROM CTE
INNER JOIN tbl_Container T
ON CTE.Container = T.From_Container
AND CTE.Part_Key = T.Part_Key
)
SELECT Part_Key, SUM(T1.Extended_Cost) Sum_Extended_Cost FROM CTE T1
WHERE
EXISTS( SELECT * FROM
CTE T2 WHERE
T1.Operation = T2.Operation
AND T1.I > T2.I )
GROUP BY Part_Key
Result:
Part_Key Sum_Extended_Cost
---------- -----------------
PN_100 40

Running counts of records and sum of max() records within date range based specified intervals in t-sql

Sample data: (assume year_month_record is the first day of the month and is datetime data type)
location item year_month_record type visits1 visits2
ABC111 11JF445553 2014-01 sales 3 5
ABC111 11JF445553 2014-02 sales 3 6
ABC111 11JF445553 2014-03 sales 2 8
ABC111 11JF445553 2014-04 sales 2 4
ABC111 22WZ777814 2014-02 sales 3 5
ABC111 55RR342013 2014-01 nsales 1 2
For the given sample data, I need to count how many times records with the same location and item appear within specified intervals. In addition, I need to grab the maximum value for specified interval / time frame and sum it up based on location, item_number and type.
The output should look something like this:
location year_month_record length_months type count_unique_visits sum_max_visits1 sum_max_visits2
ABC111 2014-01 3 sales 4 6 13
ABC111 2014-02 3 sales 4 6 12
ABC111 2014-03 3 sales 2 4 12
ABC111 2014-04 3 sales 1 2 4
ABC111 2014-01 3 nsales 1 1 2
notes for calculating visits1 / visits2 above
example output of record 1: max(of item 11JF445553) = 3 + max(item 22WZ77781) = 3. Sum = 6 (item 55RR342013 has a different type). Note 2. All records with max summed up are within "length_months" specified of 3 months. 2014-01 through 2014-03.
new "type" will cause new grouping to start
Additional notes:
count_unique_visits is the count for each record within date range
length_months is defined prior to execution and can be hardcoded
current year_month_record + length_months (i.e. 2014-01 year_month_record with length_months = 3) is 01/2014 through 03/2014
I've tried creating a recursive CTE to select the count and max, but i'm doing something wrong.
Basically, I need to be able to recursively, grab a count and the max visit1/2 for a given interval.
Starting with 01/2014, it would need to look for the max(visits1/2) for the next three months (basically, 01/2014 - 04/2014) and return those. In 02/2014, it would use the range of 02/2014 through 05/2014 and return the max there as well. It would continue this throughout the recordset. The interval would be 3 months, but then I could copy the query and replace with 6 months and so on and so forth.
Closing this topic to ask a more targeted/specific question.
Any help would be appreciated.
You can use a combination of a groupping subquery followed by a cross apply subquery:
DECLARE #len int = 3
SELECT grp.*, SUM(ca.cuv) count_unique_visits, SUM(ca.visits1) sum_max_visits1, SUM(ca.visits2) sum_max_visits2
FROM
(SELECT v.location, v.year_month_record, v.type
FROM Visits v
GROUP BY v.location, v.year_month_record, v.type) grp CROSS APPLY
(SELECT COUNT(*) cuv, MAX(visits1) visits1, MAX(visits2) visits2
FROM Visits ca_v
WHERE ca_v.location = grp.location AND grp.type = ca_v.type AND ca_v.year_month_record >= grp.year_month_record AND
ca_v.year_month_record < DATEADD(month, #len, grp.year_month_record)
GROUP BY ca_v.item
) ca
GROUP BY grp.location, grp.year_month_record, grp.type
ORDER BY grp.type DESC, grp.year_month_record
You can see the results in this SQLFiddle.
NOTE: As I wrote in the comment to the original question, I suspect you have a mistake in the requested output, if not, please explain...

Select rows where count() = n

I'm implementing a search functionality where the results should show results page and for each result, the main image and up to 3 more thumbnails.
Right now in the procution version, for each ad it makes 1 select to return the images from the database which it terrible for performance, so I've changed it to a single query that does basically the following:
select * from AdImages order by IsMainImage desc, AdImageId
and returns something like:
AdImageId AdId IsMainImage FilePath
----------- ----------- ----------- ----------------------------------------
1 1 1 9c513f10-5480-4e41-89c6-074b36051999.jpg
5 2 1 f64f9c12-398e-445f-9724-baebe40930b1.jpg
6 4 1 8187d566-b296-4ab0-85e5-b9fc86f293b7.jpg
8 5 1 b8165008-09b3-4258-bf54-043195138344.jpg
10 6 1 86c636ed-f4ed-4f7e-8c7e-fc0b24faa956.jpg
11 7 1 4409a3fd-2bc0-4512-9850-6f5146193e50.jpg
13 8 1 b9b66c48-92b7-479a-a85d-dc6d26b03ebc.jpg
14 9 1 9f3f06ad-4fe1-43a5-8cce-3bb804bb10b7.jpg
16 10 1 016c30dc-5ee8-40d8-9d0f-398f444d7a7b.jpg
19 11 1 e5e56602-1af7-492b-8a8e-b61ac86b751b.jpg
2 1 0 02d44ce1-0de6-4e22-b4ef-043a72e9b5e8.jpg
3 1 0 8c4e19db-faff-44c2-9aab-6a96ab2a8e22.jpg
4 1 0 d8c2464a-277c-40fa-ab43-d2455e819e7e.jpg
7 4 0 d1430ae0-df51-43b7-acea-50d606eee5ba.jpg
9 5 0 b947ae4c-653d-4c27-9edd-567d977e1af3.jpg
12 7 0 3080c947-3769-4762-bb29-f1f9c5303ecd.jpg
15 9 0 d2543ce3-1e65-4a18-80d6-584de0025f1a.jpg
17 10 0 03b26d6a-4e0c-4393-9b5a-d9f2a24d36da.jpg
18 10 0 cde5dacd-3984-4cea-b56f-c3a6c5b82fa0.jpg
20 11 0 9e286ac0-25b1-4a05-af83-26e5d0002c2a.jpg
21 11 0 b1266770-9926-462c-8ec0-e965b21021eb.jpg
22 11 0 0542bd2a-4c4b-41d4-b51b-d311f42f0da9.jpg
23 11 0 b1cc44c9-50c4-4e81-bc9a-a0a4b515e709.jpg
My local db is very small but I could notice a very good performance gain, anyway, I think it could be better if I could make this query return only up to 4 rows for each ad instead of all the rows for each ad as it is doing. But to do so, it should be something like where count(AdId) == 4 which I'm not sure is possible.
I'm also using Entity Framework here. Any extra advice would be very welcome.
Use Window Function
select AdImageId ,AdId ,IsMainImage ,FilePath
from(
select row_number() over(partition by Adid order by IsMainImage desc, AdImageId) rn,*
from AdImages)a
where rn<=4
If I am understanding you correctly, you can just return the TOP xx results.
SELECT TOP(3) * from AdImages order by IsMainImage desc, AdImageId;
This will return only the top 3 results.

Resources