ACCESS/SQL: Calculating the difference between rows (not dates) - sql

I looked through the questions here but didn't find one that suited my case.
I'm trying to write a query that will output the difference between rows
Here is a table:
ITEM CYCLES
--------------------
itemA 5
itemA 17
itemA 20
itemA 22
itemB 26
itemB 30
itemB 37
it is actually obtained by a query, and with an order by (item, cycles)
here is what I'd like the query to give me:
itemA 12
itemA 3
itemA 2
itemB 4
itemB 7
I have absolutely no idea how to proceed in SQL. Is it even possible ?
or do I have to write a function ?
*****************************EDIT*********************************
I appologize for the lack of precision, and even some absurd mistakes. I was rushing out and wrote hastily :/
I'm analyzing item failures, and need to output cycles between failures.
ITEM column is just the item ID, and
CYCLES is the number of cycles the item had when the failure occurred.
And actually looking at it today I don't understand why I put that middle column (A,B,C...) which I don't have in my table.
And indeed, I don't need to output zero values, but there shouldn't be any anyway.
I'll try the provided solutions and will get back; thanks for the answers !

Here's an updated solution, based on the changes to your question. Note that you'll need to change Qry to the name of your query:
SELECT Qry.Item, Qry.Cycles - (SELECT TOP 1 Cycles FROM Qry AS Q
WHERE Qry.Item=Q.Item
AND Q.Cycles < Qry.Cycles
ORDER BY Q.Cycles DESC) AS Diff
FROM Qry
WHERE (SELECT TOP 1 Cycles FROM Qry AS Q
WHERE Qry.Item=Q.Item AND Q.Cycles < Qry.Cycles) Is Not Null
ORDER BY Qry.Item, Qry.Cycles;
This produces the following output:
Item Diff
itemA 12
itemA 3
itemA 2
itemB 4
itemB 7
I assume that the 6 in your sample output was a typo, since 30 - 26 = 4.

Assuming our columns are named ItemName, Letter, Num, something like the following might do it:
SELECT T1.ItemName, T1.Letter
, T1.Num, [T2].[Num]-Nz([T1].[Num],[T2].[Num]) AS Expr1
FROM Table1 AS T1
LEFT JOIN Table1 AS T2
ON (T1.ItemName = T2.ItemName
And Asc([T1].[Letter]) = Asc([T2].[Letter]) - 1 )
Where [T2].[Num] <> Nz([T1].[Num],[T2].[Num])
Note that you cannot create this using the QBE grid. You would need to create in code or in the SQL View.

How about:
SELECT b.Item, b.[No], (
SELECT Top 1 a.No
FROM items a
WHERE a.No > b.No
ORDER BY a.Item,a.No) AS NextNo,
[NextNo]-[No] AS Result
FROM items AS b;

This is much simpler if you have a fourth column with an ID:
Col0 Col1 Col2 Col3
1 itemA A 5
2 itemA B 17
3 itemA C 20
4 itemA D 22
5 itemB A 26
6 itemB B 30
7 itemB C 37
Then you can use the following query:
SELECT Tbl.Col1, Tbl.Col3 - Prev.Col3 AS Diff
FROM Tbl INNER JOIN Tbl AS Prev
ON Tbl.Col0 - 1 = Prev.Col0
AND Tbl.Col1 = Prev.Col1
To produce exactly what you requested:
Col1 Diff
itemA 12
itemA 3
itemA 2
itemB 4
itemB 7
You would need to manage the Col0 data to make sure you don't end up with gaps (ie, Autonumber field would be a bad idea).
All of the above having been said, if you let us know what you are really trying to accomplish I'm thinking there is probably a better way to do what you want.

Related

Create multiple rows based on 1 column

I currently have a table with a quantity in it.
ID Code Quantity
1 A 1
2 B 3
3 C 2
4 D 1
Is there anyway to write a sql statement that would get me
ID Code Quantity
1 A 1
2 B 1
2 B 1
2 B 1
3 C 1
3 C 1
4 D 1
I need to break out the quantity and have that many number of rows
Thanks
Here's one option using a numbers table to join to:
with numberstable as (
select 1 AS Number
union all
select Number + 1 from numberstable where Number<100
)
select t.id, t.code, 1
from yourtable t
join numberstable n on t.quantity >= n.number
order by t.id
Online Demo
Please note, depending on which database you are using, this may not be the correct approach to creating the numbers table. This works in most databases supporting common table expressions. But the key to the answer is the join and the on criteria.
One way would be to generate an array with X elements (where X is the quantity). So for rows
ID Code Quantity
1 A 1
2 B 3
3 C 2
you would get
ID Code Quantity ArrayVar
1 A 1 [1]
2 B 3 [1,2,3]
3 C 2 [2]
using a sequence function (e.g, in PrestoDB, sequence(start, stop) -> array(bigint))
Then, unnest the array, so for each ID, you get a X rows, and set the quantity to 1. Not sure what SQL distribution you're using, but this should work!
You can use connect by statement to cross join tables in order to get your desired output.
check my solution it works pretty robust.
select
"ID",
"Code",
1 QUANTITY
from Table1, table(cast(multiset
(select level from dual
connect by level <= Table1."Quantity") as sys.OdciNumberList));

How to arrange Sql rows in a specific format

I have table with up to 50 rows... like given below.
ID menu dispOdr ParntID
---------------------
1 abc 1 0
2 cde 2 0
3 fgh 1 2
4 ghdfdj 2 2
5 tetss 1 1
6 uni 3 0
but I want to be sorted
Like
ID menu dispOdr ParntID
---------------------
1 abc 1 0
5 tetss 1 1
2 cde 2 0
3 fgh 1 2
4 ghdfdj 2 2
6 uni 3 0
If have any query please let me know.. thanks in advance.
I am using sql server 2014
I think you need your current vs. desired output reversed. You say you want the menu column sorted, but it appears that it already is.
So assuming you are actually starting with the second table, you can sort the menu column simply using ORDER BY:
SELECT *
FROM mytable
ORDER BY menu ASC
I think that the query below produces the required output:
SELECT t1.ID, t1.menu, t1.dispOdr, t1.ParntID
FROM mytable AS t1
LEFT JOIN mytable AS t2 ON t1.ParntID = t2.ID
ORDER BY CASE
WHEN t1.ParntID = 0 THEN t1.dispOdr
ELSE t2.dispOdr
END,
CASE
WHEN t1.ParntID = 0 THEN 1
ELSE 2
END,
t1.dispOdr
The first CASE expression groups records according to the dispOdr of their parent. The second CASE places parent on the top of its subgroup. Finally, the last expression used in the ORDER BY clause orders all child records within a subgroup.
Note: The above query works with one level of nesting.

MS Access 2010 SQL Top N query by group performance issue (continued2)

I have rephrased a previous question MS Access 2010 SQL Top N query by group performance issue (continued) as I believe the context was not clearly described before. The anwwer to my previous question did not provide the top n by group result. The rephrased question is more generic. I have now all data in one table.
Here is my situation: I have a table (Analysis) that contains products (Partnumber) of various categories (Category). Every product has a price (Value). The objective of the query is to show the 10 products with the highest price of each category The table contains 15000 records and will continue to grow.
This is the query:
SELECT
a.Location,
a.Category,
a.Partnumber
a.Value
FROM Analysis a
WHERE a.Partnumber IN (
SELECT TOP 10 aa.Partnumber
FROM Analysis aa
WHERE aa.Category = a.Category
ORDER BY aa.Value DESC
)
ORDER BY
a.Category;
Here is my question: My current query works with 1000 records in the table (respond time 3 seconds). With 15000 records the query runs endlessly long. How can I rebuild the query to significantly improve performance?
The answer to my previous question was to not use the in-list operation. But this eliminated function to give the top n records by group. The query gave the top n of all records.
For sample data in a table called [Analysis]
ID Location Category Partnumber Value
-- --------- -------- ---------- -----
1 here cat1 part001 1
2 there cat1 part002 2
3 wherever cat1 part003 3
4 someplace cat2 part004 4
5 nowhere cat2 part005 5
6 unknown cat2 part006 6
the "ranking query"
SELECT
a1.ID,
a1.Location,
a1.Category,
a1.Partnumber,
a1.Value,
COUNT(*) AS CategoryRank
FROM
Analysis a1
INNER JOIN
Analysis a2
ON a1.Category = a2.Category
AND a1.Value <= a2.Value
GROUP BY
a1.ID,
a1.Location,
a1.Category,
a1.Partnumber,
a1.Value
returns
ID Location Category Partnumber Value CategoryRank
-- --------- -------- ---------- ----- ------------
1 here cat1 part001 1 3
2 there cat1 part002 2 2
3 wherever cat1 part003 3 1
4 someplace cat2 part004 4 3
5 nowhere cat2 part005 5 2
6 unknown cat2 part006 6 1
so if you only want the top 2 items in each category just wrap the above query in a SELECT ... WHERE
SELECT *
FROM
(
SELECT
a1.ID,
a1.Location,
a1.Category,
a1.Partnumber,
a1.Value,
COUNT(*) AS CategoryRank
FROM
Analysis a1
INNER JOIN
Analysis a2
ON a1.Category = a2.Category
AND a1.Value <= a2.Value
GROUP BY
a1.ID,
a1.Location,
a1.Category,
a1.Partnumber,
a1.Value
) AS RankingQuery
WHERE CategoryRank <= 2
ORDER BY Category, CategoryRank
to give you
ID Location Category Partnumber Value CategoryRank
-- -------- -------- ---------- ----- ------------
3 wherever cat1 part003 3 1
2 there cat1 part002 2 2
6 unknown cat2 part006 6 1
5 nowhere cat2 part005 5 2
Note: Ensure that the [Category] and [Value] fields are indexed for best performance.

SQL Server Concatenate Rows Using Many-To-Many Related Tables

I've already searched for my problem, but most of the examples (if not all), have to deal with only one or two tables with a one-to-many relationship between them.
So, here goes my scenario:
My first table is:
OrderID Quantity Price
----------------------------------
18 1000.00 160.00
19 1000.00 40.00
22 1000.00 40.00
23 100.00 500.00
24 10.00 50.00
My second table is:
ExtrasID Name
-------------------
1 Value 1
2 Value 2
3 Value 3
4 Value 4
5 Value 5
I have a many-to-many relationship established between the tables above, so there is a third (joint) table which is as follows:
OrderExtrassID OrderExtras_OrderID OrderExtras_ExtrasID
----------------------------------------------------------------
20 19 2
22 22 3
23 23 2
24 23 5
Now, all I want to achieve is to get a result such as the following:
OrderID Extras
----------------------------
18 NULL
19 Value 2
22 Value 3
23 Value 2, Value 5
24 NULL
There are many examples using XML PATH, PIVOT, CTE etc., but none of these seems to help me with my scenario, or at least I've not managed to study them in depth, in order to get my work done...
Thanks in advance,
I would suggest using For XML to return multiple rows into a single row and then using STUFF to removing the extra comma. Something like this:
SELECT O.OrderId
,STUFF(
(
SELECT ',' + E.Name AS [text()]
FROM OrderExtras OE
Inner Join Extras E
ON E.ExtrasId = OE.OrderExtras_ExtrasID
WHERE O.OrderId = OE.OrderExtras_OrderID
ORDER BY E.Name
FOR XML PATH('')
), 1, 1, '') AS ColList
FROM Orders O
And here is the SQL Fiddle.
Good luck.

Difficulty in creating update totals query on same table

Consider the following table:
ID nonUniqueID value total
--------------------------
1 12345 5 x
2 12345 10 x
3 789 20 x
4 789 5 x
I need to make a query something like this (psuedo SQL), which will work within Access 2007:
UPDATE table
SET total = SUM(value)
WHERE nonUniqueID IS SAME;
The result should be as follows:
ID nonUniqueID value total
--------------------------
1 12345 5 15
2 12345 10 15
3 789 20 25
4 789 5 25
I've tried group bys, but I got odd results that quite frankly, I could not interpret. Does anybody know how I could achieve something like this?
Not sure if this works in Access or not, but give it a try:
update table t1
inner join (
select nonUniqueID, sum(value) as SumValue
from table
group by nonUniqueID
) t2 on t1.nonUniqueID = t2.nonUniqueID
set t1.total = t2.SumValue
Update: Based on this question, it looks like it is not going to work. But give it a shot! If it doesn't, you can use the approach suggested in that question.
Another possible option:
update t
set total = (select SUM(value) from table where nonUniqueID = t.nonUniqueID)
from table t