i have a table like this. If times increas i expect to increase Rating column but sometimes rating column decrease. I want to find how many times decrease this table. In this example rating column 2 times decrease (4-->2 and 3--> 1 ) i want to this 2 number in query. Also times column every time increase.How can i write this situation's sql query. (note: i am using DB2 DBMS)
Rating times
1 20.09.2016
2 21.09.2016
3 22.09.2016
4 23.09.2016
2 24.09.2016
3 25.09.2016
1 26.09.2016
Thanks,
SELECT COUNT(1) AS COUNT_OF_TIMES_RATING_GOT_DECREASED
FROM
(
SELECT rating,
times,
rating - LEAD( rating, 1 ) OVER ( ORDER BY times ) AS diff_rating
FROM table
)
WHERE diff_rating > 0;
Without those functions being available, e.g. with the DB2 for i, the following should suffice [easily omitting the fluff I add to make a pretty report, and/or optionally correcting my inclusion of the row_number to reveal the from/to instead of showing the "times" values that exhibit that decreasing transition]:
create table ratings
( "rating" for r dec
, "times" for t date
)
;
insert into ratings values
/* Rating times */
( 1 , '20.09.2016' )
, ( 2 , '21.09.2016' )
, ( 3 , '22.09.2016' )
, ( 4 , '23.09.2016' )
, ( 2 , '24.09.2016' )
, ( 3 , '25.09.2016' )
, ( 1 , '26.09.2016' )
;
with
ord_ratings as
( select row_number() over(order by "times) as rn
, "rating"
from ratings
)
select 'From' as "From"
, dec(a.rn, 6) as rn_a
, 'to' as "to"
, dec(b.rn, 6) as rn_b
, a."rating" as rating_a
, '-->' as "-->"
, b."rating" as rating_b
from ord_ratings a
join ord_ratings b
on a.rn = ( b.rn - 1 )
and b."rating" < a."rating"
; -- a likeness of the report from the above query:
"From" RN_A "to" RN_B RATING_A "-->" RATING_B
From 4 to 5 4 --> 2
From 6 to 7 3 --> 1
******** End of data ********
Related
I have two tables: table 1 a package_id and a timestamp column for which I have no weight information available, table 2 a package_id, a timestamp and a weight column where I do have the information.
What I'm trying to do is fill in the table 1 weight information based on table 2 using the following restrictions:
use the closest package_id available ie. for package_id 1 use 2 if available, if not 3 etc
if there is only one weight available use it for all the missing package_id's
if two weights are available, use the higher one ie. for package_id 5, if 4 and 6 are available use 6
The code:
IF OBJECT_ID('tempdb..#TIMEGAPS') IS NOT NULL DROP TABLE #TIMEGAPS
CREATE TABLE #TIMEGAPS (PACK_ID INT, Local_Time DATETIME)
IF OBJECT_ID('tempdb..#REALVALUES') IS NOT NULL DROP TABLE #REALVALUES
CREATE TABLE #REALVALUES (PACK_ID INT, Local_Time DATETIME, WEIGHT INT)
INSERT INTO #TIMEGAPS VALUES
(1,'2018-01-20 18:40:00.000'),
(1,'2018-01-20 18:50:00.000'),
(1,'2018-01-20 19:00:00.000'),
-----------------------------
(7,'2018-01-20 18:40:00.000'),
(7,'2018-01-20 18:50:00.000'),
(7,'2018-01-20 19:00:00.000'),
------------------------------
(12,'2018-01-20 18:40:00.000'),
(12,'2018-01-20 18:50:00.000'),
(12,'2018-01-20 19:00:00.000'),
(12,'2018-01-20 20:00:00.000')
INSERT INTO #REALVALUES VALUES
(2,'2018-01-20 18:40:00.000',50),
(3,'2018-01-20 18:40:00.000',70),
(4,'2018-01-20 18:40:00.000',150),
(5,'2018-01-20 18:40:00.000',60),
(6,'2018-01-20 18:40:00.000',45),
(8,'2018-01-20 18:40:00.000',55),
(9,'2018-01-20 18:40:00.000',25),
---------------------------------
(2,'2018-01-20 18:50:00.000',75),
(3,'2018-01-20 18:50:00.000',80),
(4,'2018-01-20 18:50:00.000',120),
(5,'2018-01-20 18:50:00.000',110),
(11,'2018-01-20 18:50:00.000',30),
---------------------------------
(8,'2018-01-20 19:00:00.000',70)
EDIT:
I've adapted the solution from here which I believe is what I need.
SELECT tg.PACK_ID, tg.Local_Time, p.WEIGHT
FROM #TIMEGAPS tg
OUTER APPLY
(
SELECT TOP 1 *, ABS(tg.PACK_ID - rv.PACK_ID) AS diff
FROM #REALVALUES rv
WHERE (tg.Local_Time = rv.Local_time OR rv.Local_time is null)
ORDER BY CASE WHEN rv.Local_time IS NULL THEN 2 ELSE 1 END,
ABS(rv.PACK_ID- tg.PACK_ID) ASC
) p
EDIT 2:
3. if two weights are available, use the highest PACK_ID ie. for package_id 5, if PACK_ID 4 and PACK_ID 6 are available use 6
Something like this?
It uses a row_number by distance.
SELECT
PACK_ID, Local_Time, WEIGHT
FROM (
SELECT g.PACK_ID, g.Local_Time, v.WEIGHT,
ROW_NUMBER() OVER (PARTITION BY g.PACK_ID, g.Local_Time
ORDER BY ABS(v.PACK_ID - g.PACK_ID), v.PACK_ID DESC) AS RN
FROM #TIMEGAPS AS g
JOIN #REALVALUES AS v ON v.Local_Time = g.Local_Time
) AS q
WHERE RN = 1
ORDER BY PACK_ID, Local_Time
I suppose we can start here. Make sure to initialize your tables before you run this. I assumed that #TIMEGAPS has a weight column based on your output.
DECLARE
#Pack_id INT
, #Weight_id INT
, #mloop INT = 0
DECLARE #possible TABLE (
id INT IDENTITY (1,1)
, pack_id INT
, weight )
BEGIN_LABEL:
SELECT TOP 1 #pack_id = PACK_ID
FROM #TIMEGAPS AS g
WHERE g.WEIGHT IS NULL
ORDER BY PACK_ID ASC
IF #pack_id IS NULL
BEGIN
PRINT 'Done'
EXIT
END
INSERT INTO #possible (pack_id , weight )
SELECT PACK_ID , WEIGHT
FROM #REALVALUES as r
LEFT JOIN #TIMEGAPS as g
ON g.WEIGHT = r.PACK_ID
WHERE g.WEIGHT IS NULL
ORDER BY ABS(#pack_id - PACK_ID) ASC , WEIGHT DESC
SELECT TOP 1 #Weight_id = weight
FROM #possible
ORDER BY id ASC
IF (#Weight_id IS NULL)
BEGIN
RAISERROR('No Weights available' , 18 , 1)
EXIT
END
UPDATE #TIMEGAPS
SET WEIGHT = #Weight_id
WHERE PACK_ID = #Pack_id
SET #mloop = #mloop + 1
IF #mloop > 99
BEGIN
PRINT 'Hit Safety'
EXIT
END
SELECT #Pack_id = NULL , #Weight_id = NULL;
DELETE #possible;
GOTO BEGIN_LABEL
SELECT g.PACK_ID , g.Local_Time , r.WEIGHT
FROM #TIMEGAPS AS g
INNER JOIN #REALVALUES AS r
r.PACK_ID = g.WEIGHT;
Im pretty sure RAISERROR() works in SQL 2008, but you can just replace them with print statements if they don't
Example table:
Sample
------
id (primary key)
secondaryId (optional secondary key)
crtdate (created date)
... (other fields)
Some users use secondaryId for identifying rows (i.e., should be unique)
When the rows were created, secondaryId did not get a value, and was defaulted to 0.
Subsequently, rows were given a secondaryId value as they were used.
I need to update all rows with value 0 to be the next available number.
Desired result (w/ simplified values):
From: To:
id secondaryId id secondaryId
1 0 1 7 // this is the max(secondaryId)+1
2 0 2 8 // incrementing as we fill in the zeroes
3 5 3 5 // already assigned
4 0 4 9 // keep incrementing...
5 6 5 6 // already assigned
This query would accomplish what I want to do; but alas, CTE + UPDATE is not supported:
with temp(primary, rownumber) as (
values (
select
id,
row_number() over (partition by secondaryId order by crtdate)+6 --6 is max secondaryId
from Sample
where secondaryId='0'
)
update Sample set secondaryId=temp.rownumber where Sample.id=temp.id
Does anyone have suggestions for a different way to approach this problem? I'm now suffering from tunnel vision...
You can use MERGE statement as id is primary key and there won't be any duplicates.
MERGE INTO Sample as trgt
Using (
select id,
row_number() over (partition by secondaryId order by crtdate)+6 secondaryId
--6 is max secondaryId
from Sample where secondaryId='0'
) as src
ON( src.id= trgt.id)
WHEN MATCHED THEN UPDATE SET trgt.secondaryid = src.secondaryId
You can also UPDATE a SELECT (well "fullselect"), which is probably the neatest solution here
create table sample (
id int not null primary key
, secondaryId int not null
, crtdate date not null
)
;
INSERT INTO sample VALUES
( 1 , 0 , current_date)
,( 2 , 0 , current_date)
,( 3 , 5 , current_date)
,( 4 , 0 , current_date)
,( 5 , 6 , current_date)
;
UPDATE (
SELECT id, secondaryId
, ROW_NUMBER() OVER(ORDER BY secondaryId Desc)
+ (SELECT MAX(id) from sample) as new_secondaryId
FROM
sample s
WHERE secondaryId = 0
)
SET secondaryId = new_secondaryId
;
https://www.ibm.com/support/knowledgecenter/en/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0001022.html
For a Template method (not necessary to know max value), you can try this:
create table tmptable as (
select f1.id, row_number() over(order by f1.crtdate) + ifnull((select max(f2.secondaryId) from Sample f2), 0) newsecondary
from Sample f1 where f1.secondaryId='0'
) with data;
update Sample f1
set f1.secondaryId=(
select f2.newsecondary
from tmptable f2
where f2.id=f1.id
)
where exists
(
select * from tmptable f2
where f2.id=f1.id
);
drop table tmptable;
I am working on building Test Case Manager database where each test case can have a set of test steps.
I created a Test Case table, which has as one of its fields a foreign key to the Test Step Groups table. The Test Step Groups table represents sets of test steps. There is a separate Test Step table to contain rows of test step data.
Each Test Case may contain any number of test steps. I want to be able to re-use sets of test steps, because sometimes test cases re-use sets of steps and then add on other steps. It's not a hierarchical structure, of course, more of an n-tuple structure.
So how do I define in the schema a representation of a Test Case with any number of test steps?
To be able to reuse the groups and steps for your test cases I think you will need 2 linking tables between your 3 entities, so that the cases aren't tied to groups and groups aren't tied to steps.
Something along the lines of this might provide you with a dummy scenario:
CREATE TABLE #temp_case
(
case_id INT ,
case_name VARCHAR(10)
)
CREATE TABLE #temp_case_group
(
case_id INT ,
group_id INT
)
CREATE TABLE #temp_group ( group_id INT )
CREATE TABLE #temp_group_steps
(
group_id INT ,
step_id INT
)
CREATE TABLE #temp_steps
(
step_id INT ,
step_name VARCHAR(10)
)
INSERT INTO #temp_case
( case_id, case_name )
VALUES ( 1, 'CASE 1' ),
( 2, 'CASE 2' ),
( 3, 'CASE 3' )
INSERT INTO #temp_case_group
( case_id, group_id )
VALUES ( 1, 6 ),
( 2, 6 ),
( 3, 7 )
INSERT INTO #temp_group
( group_id )
VALUES ( 6 ),
( 7 )
INSERT INTO #temp_group_steps
( group_id, step_id )
VALUES ( 6, 10 ),
( 6, 11 ),
( 6, 14 ),
( 7, 10 ),
( 7, 12 ),
( 7, 14 )
INSERT INTO #temp_steps
( step_id, step_name )
VALUES ( 10, 'first step' ),
( 11, 'foo step' ),
( 12, 'bar step' ),
( 14, 'last step' )
SELECT tc.case_id ,
tc.case_name ,
tg.group_id ,
ts.step_id ,
ts.step_name
FROM #temp_case tc
INNER JOIN #temp_case_group tcg ON tcg.case_id = tc.case_id
INNER JOIN #temp_group tg ON tg.group_id = tcg.group_id
INNER JOIN #temp_group_steps tgs ON tgs.group_id = tg.group_id
INNER JOIN #temp_steps ts ON ts.step_id = tgs.step_id
ORDER BY tc.case_id ,
tcg.group_id ,
ts.step_id
DROP TABLE #temp_case
DROP TABLE #temp_case_group
DROP TABLE #temp_group
DROP TABLE #temp_group_steps
DROP TABLE #temp_steps
Output:
case_id case_name group_id step_id step_name
1 CASE 1 6 10 first step
1 CASE 1 6 11 foo step
1 CASE 1 6 14 last step
2 CASE 2 6 10 first step
2 CASE 2 6 11 foo step
2 CASE 2 6 14 last step
3 CASE 3 7 10 first step
3 CASE 3 7 12 bar step
3 CASE 3 7 14 last step
So you can see, CASE 1 and CASE 2 share the same group, and therefore contain the same steps. CASE 3 uses it's own group but shares the first and last step with the other group.
This will allow groups of steps to be reused on different test cases, and allow steps to be reused across different groups, which is hopefully what you're after.
I have a stored procedure that I would like to output a row count that is divisible by 15. For example, I have this stored procedure that outputs 33 rows but each page holds exactly 15 rows. On the last page that only has 3 rows, the spacing is messed up. Because the row count is always dynamic, I thought it would be easier to make the row count a number that is divisible by 15. So in this case, it would add 12 blank rows to keep the spacing correct.
Here is my code:
SELECT ROW_NUMBER() OVER ( ORDER BY YEAR(rce.Ecodate) ) AS Row ,
rce.ReportRunCaseId AS CaseId ,
YEAR(rce.EcoDate) AS EcoYear ,
SUM(rce.NetInv) AS NetInvSum ,
SUM(rce.NDCash) AS NDCashSum ,
SUM(rce.DiscCash) AS DiscCashSum ,
SUM(rce.GrossGas) AS GrossGasSum ,
SUM(rce.GrossOil) AS GrossOilSum ,
SUM(rce.NetProdTax) AS NetProdTaxSum ,
SUM(rce.NetOpCost) AS NetOpCostSum ,
SUM(rce.WellCost) AS WellCostSum ,
SUM(rce.NetOil) AS NetOilSum ,
SUM(rce.CoNetRevOil) AS CoNetRevOilSum ,
SUM(rce.CoNetRevGas) AS CoNetRevGasSum ,
SUM(rce.NetGas) AS NetGasSum ,
rce.WellCount ,
rcl.SortId
FROM PhdRpt.ReportCaseList AS rcl
INNER JOIN PhdRpt.RptCaseEco AS rce ON rce.ReportId = rcl.ReportId
AND rce.ReportRunCaseId = rcl.ReportRunCaseId
GROUP BY rcl.SortId ,
rce.ReportId ,
rce.ReportRunCaseId ,
YEAR(rce.EcoDate) ,
rce.WellCount
I have read that I can use INSERT INTO to add rows to the table. Should I use something like this:
INSERT INTO rce
SELECT num - 1
FROM T1
WHERE ( num % 15 ) = 0
Insert the records you are selecting in the example into a temp
table.
Then issue another insert into the temp table for the blank
rows that you want to add.
Then select the records from the temp
table as the return value for the stored proc.
I have three tables
shipment (shipment_id, shipping_date)
company_order (company_order_id, shipment_id, company_id)
company_order_item (company_order_item_id, company_order_id, product_id)
Several companies get together and aggregate orders from a single manufacturer. This aggregate order is called a "shipment". Companies order a selection of products in each shipment: so not all products will be present in any one shipment or for any one company.
How do I write an SQL query find the most recent shipment for each product_id ?
I've looked at
SQL Query - Get Most Recent Revision (much simpler case).
You need to get the max shipment date per product id and then retrieve the shipment detaisl
Something like
SELECT *
FROM (
SELECT coi.product_id,
MAX(s.shipping_date) MaxDate
FROM company_order_item coi INNER JOIN
company_order co ON coi.company_order_id = co.company_order_id INNER JOIN
shipment s ON co.shipment_id =s.shipment_id
GROUP BY coi.product_id
) sub INNER JOIN
company_order_item coi ON sub.product_id = coi.product_id INNER JOIN
company_order co ON coi.company_order_id = co.company_order_id INNER JOIN
shipment s ON co.shipment_id = s.shipment_id
AND s.shipping_date = sub.MaxDate
SQL Code to illustrate - (This is T-SQL and is SQL Server friendly, but i didn't have any mysql handy. The last query should with tiny modifications (to suit your table names) work nicely in MySQL as well.
My logic is to find the most recent company_order for each product_id. Once i have that i can just join the company_order_id to company_order, and i have the shipment_id for each most-recent company_order per product_id
DROP TABLE #shipment
DROP TABLE #company_order
DROP TABLE #company_order_item
CREATE TABLE #shipment
(
shipment_id INT ,
shipping_date INT
) ;
CREATE TABLE #company_order
(
company_order_id INT ,
shipment_id INT ,
company_id INT
) ;
CREATE TABLE #company_order_item
(
company_order_item_id INT ,
company_order_id INT ,
product_id INT
) ;
INSERT INTO #shipment
( shipment_id , shipping_date )
VALUES
( 1 , 1 ),
( 2 , 2 ),
( 3 , 3 )
INSERT INTO #company_order
( company_order_id , shipment_id , company_id )
VALUES
( 1 , 1 , 1 ),
( 2 , 2 , 1 ),
( 3 , 3 , 1 )
INSERT INTO #company_order_item
( company_order_item_id , company_order_id , product_id )
VALUES
( 1 , 1 , 1 ) ,
( 2 , 1 , 2 ),
( 2 , 2 , 2 ),
( 1 , 1 , 3 ),
( 1 , 3 , 4 )
SELECT
product_id ,
shipment_id
FROM
(
SELECT
product_id ,
MAX(company_order_id) AS company_order_id
FROM
#company_order_item
GROUP BY
product_id
) AS MostRecentProductInOrder
INNER JOIN #company_order
ON MostRecentProductInOrder.company_order_id = #company_order.company_order_id