How to using loop with oracle query? - sql

Here is a query in a procedure where I pull the data and write it to the table:
SELECT
SUBSTR(sl.TASK_JOB_ID,1,12) AS schedule_id,
null AS schedule_seq,
null AS schedule_subseq,
BULK COLLECT
INTO
v_schedule_detail_table
FROM
sch_line sl,
SCH_INPUT_MATERIAL sim ,
SCH_INPUT_PIECE sip,
SCH_PIECES_RELATION spr,
SCH_CUT sc
WHERE
sl.TASK_JOB_ID = v_schedule_table(i).schedule_id
AND sl.SCH_LINE_NUM_ID = sim.SCH_LINE_NUM_ID
AND sim.INPUT_MAT_NUM_ID = sip.INPUT_MAT_NUM_ID
AND sip.INPUT_PIECE_NUM_ID = spr.INPUT_PIECE_NUM_ID
AND spr.SCHC_CUT_NUM_ID = sc.SCHC_CUT_NUM_ID;
When this code gets the data in sch_cut table , I want to fills schedule seq and schedule_subseq as in the example below.
For an example schedule id value, the following output of the sch_cut table appears.
According to this table without taking the value of 0 in piece grouping ;
If to_cut_trans_flag = Y, then that values increment to schedule_seq
If to_cut_long_flag = Y, then that values increment to schedule_subseq
and the algorithm will be as follows
Finally the output I want to see for this example should be filled like this

Related

SQL Server: Selecting Specific Records From a Table with Duplicate Records (Excluding Stale Data from a Query)

I'm trying to put together a query (select preferably) in SQL server that works with a single table. Said table is derived from two sets of data. Records where SET = OLD represent old data, records where SET = NEW represent new data. My intention is as follows:
If record CODE = A, keep/include the record.
If record CODE = C, keep/include the record but delete/exclude the corresponding record from the old set under the same ACT value.
If record CODE = D, delete/exclude it along with its corresponding record from the old set under the same ACT value.
If CODE = '' (blank/null), keep the record but only if it exists in the OLD set (meaning their isn't a corresponding record from the new set with the same ACT value)
What the table looks like before logic is applied:
ACT|STATUS |CODE|SET|VALUE
222| | |OLD|1
333| | |OLD|2
444| | |OLD|3
111|ADDED |A |NEW|4
222|CHANGED|C |NEW|5
333|DELETED|D |NEW|6
What the table should look like after logic is applied (end result)
ACT|STATUS |CODE|SET|VALUE
444| | |OLD|3
111|ADDED |A |NEW|4
222|CHANGED|C |NEW|5
While I can probably put together a select query to achieve the end result above I doubt it will run efficiently as the table in question has millions of records. What is the best way to do this without taking a long time to obtain the end result?
Something like this. you will have to split your query and union.
--Old Dataset
SELECT O.*
FROM MyTable O
LEFT JOIN Mytable N ON O.ACT = N.ACT AND N.[SET] = 'NEW'
WHERE O.[SET] ='OLD'
AND ISNULL(N.CODE,'A') = 'A'
UNION
-- New records
SELECT N.*
FROM MyTable N
WHERE N.[SET] ='NEW'
AND CODE <> 'D'

BigQuery: Count consecutive string matches between two fields

I have two tables:
Master_Equipment_Index (alias mei) containing the columns serial_num & model_num
Customer Equipment Index (alias cei) containing the columns account_num, serial_num, & model_num
Originally, guard rails were not implemented to require model attribute input in the mei data whenever new serial_num records were inserted. Whenever that serial_num is later associated with a customer account in the cei data, the model data carries over as null.
What I want to do is backfill the missing model attributes in the cei data from the mei data based on the strongest sequential character match from other similar serial_nums in the mei data.
To further clarify, I don't have access to mass update the mei or cei datasets. I can formalize change requests, but I need to build the function out to prove its worth. So this has to be done outside of any mass action query updates.
cei.account_num
cei.serial_num
cei.model
mei.serial_num
mei.model
serial_num_str_match
row_number
123123123
B4I4SXT1708
null
B4I4SXT178A
Model_Series1
8
1
123123123
B4I4SXT1708
null
B4I4SXTAS34
Model_Series2
7
2
In the table example above row_number 1 has a higher consecutive string match count than row_number 2. I want to only return row_number 1 and populate cei.model with mei.model's value.
cei.account_num
cei.serial_num
cei.model
mei.serial_num
mei.model
serial_num_str_match
row_number
123123123
B4I4SXT1708
Model_Series1
B4I4SXT178A
Model_Series1
8
1
To give an idea as to scale:
The mei data contains 1 million records and the cei data contains 50,000 records. I would have to take and perform this string match for every single cei.account_num, cei.serial_num where the cei.model data is null.
With mac addresses, the first 6 characters identify the vendor and I could look at things similarly in the sample SQL below to help reduce the volume of transactional 1:Many lookups taking place:
/* need to define function */
create temp function string_match_function(x any type, y any type) as (
syntax to generate consecutive string count matches between x and y
);
select * from (
select
c.account_num,
c.serial_num,
m.model,
row_number() over(partition by c.account_num, c.serial_num order by serial_num_str_match desc) seq
from (
select
c.account_num,
c.serial_num,
m.model,
needed: string_match_function(c.serial_num, m.serial_num) as serial_num_str_match
from (
select * from cei where model is null
) c
join (
select * from mei where model is not null
) m on substr(c.serial_num,1,6) = substr(m.serial_num,1,6)
) as a
) as b
where seq = 1
I've looked at different options, some coming from https://hoffa.medium.com/new-in-bigquery-persistent-udfs-c9ea4100fd83, but I'm not finding what I need.
Any insight or direction would be greatly appreciated.
This UDF function counts the equal charachters in each string from the begin:
CREATE TEMP FUNCTION string_match_function(x string, y string)
RETURNS int64
LANGUAGE js
AS r"""
var i=0;
var max_len= Math.min(x.length,y.length);
for(i=0;i<max_len;i++){
if(x[i]!=y[i]) {return i;}
}
return i;
""";
select string_match_function("12a345","1234")
gives 2, because both start with 12

Complex INSERT INTO SELECT statement in SQL

I have two tables in SQL. I need to add rows from one table to another. The table to which I add rows looks like:
timestamp, deviceID, value
2020-10-04, 1, 0
2020-10-04, 2, 0
2020-10-07, 1, 1
2020-10-08, 2, 1
But I have to add a row to this table if a state for a particular deviceID was changed in comparison to the last timestamp.
For example this record "2020-10-09, 2, 1" won't be added because the value wasn't changed for deviceID = 2 and last timestamp = "2020-10-08". In the same time record "2020-10-09, 1, 0" will be added, because the value for deviceID = 1 was changed to 0.
I have a problem with writing a query for this logic. I have written something like this:
insert into output
select *
from values
where value != (
select value
from output
where timestamp = (select max(timestamp) from output) and output.deviceID = values.deviceID)
Of course it doesn't work because of the last part of the query "and output.deviceID = values.deviceID".
Actually the problem is that I don't know how to take the value from "output" table where deviceID is the same as in the row that I try to insert.
I would use order by and something to limit to one row:
insert into output
select *
from values
where value <> (select o2.value
from output o2
where o2.deviceId = v.deviceId
order by o2.timestamp desc
fetch first 1 row only
);
The above is standard SQL. Specific databases may have other ways to express this, such as limit or top (1).

sql query is not working properly

i am trying to get non matching records from two table by comparing some columns which are common in both tables.i am using sql query to get the result. my first table is snd_marketvisits this table have properties like id ,pjpCode , section code, popCode .pop_name and landmark similary my 2nd table have pjpcode , section code, popcode popname are common and there are some other fields.i want to get the names of the pop which are not in second table but present in snd_marketvisit table by comparing popcode, sectioncode and pjpcode in both tables.
SELECT *
FROM snd_marketvisits sm
LEFT JOIN snd_marketvisit_pops sp ON
sm.distributorCode = sp.distributor AND
sm.pjpCode = sp.pjp AND
sm.sectionCode = sp.sectionCode AND
sm.popCode = sp.popCode
WHERE
sm.sectionCode = '00016' AND
sm.pjpCode = '0001' AND
sm.distributorCode = '00190A'
It depends on the database, as far as I know, but if you ask for NULL inside your yoined fields you should get only the rows without a match.
SELECT *
FROM snd_marketvisits sm
LEFT JOIN snd_marketvisit_pops sp ON
sm.distributorCode = sp.distributor AND
sm.pjpCode = sp.pjp AND
sm.sectionCode = sp.sectionCode AND
sm.popCode = sp.popCode
WHERE
sm.sectionCode = '00016' AND
sm.pjpCode = '0001' AND
sm.distributorCode = '00190A'
AND sp.distributor IS NULL

Selecting more than one column to query in sql

I am having a bit of trouble, probably from my understanding of SQL. Here is the SQL I am currently using:
CREATE TEMPORARY TABLE Temp
(
sPropertyCode VARCHAR(9),
sDataDate DATE,
PRIMARY KEY (sPropertyCode)
);
INSERT IGNORE Temp (sPropertyCode, sDataDate)
SELECT sPropertyCode, sDataDate
FROM tasks as t, task_data AS d
WHERE t.iTaskId = d.iTaskId
AND iRemoved = 1
AND sDataType = 'sAgencyAgreementDate'
AND iBusinessStreamId = 9;
SELECT t.sPropertyCode, sDataDate, SFirstSeen, sTaskType
FROM tasks AS t, temp AS a
WHERE iRemoved = 1
AND iBusinessStreamId = 9
AND sTaskType IN ('RF', 'IF', 'CM')
AND t.sPropertyCode = a.sPropertyCode
ORDER BY sPropertyCode, sFirstSeen;
DROP TABLE Temp;
So the references 'RF', 'IF' and 'CM' are tasks that we receive. Each propertycode can touch each of these tasks once, and only once. I would like to show the date that each one of these was touched by the propertycode. It is working at the moment but it is showing it in three columns with the tasks types in one column. I would like each task to show in a seperate column with the date it was first seen in its own corresponding column.
So from the picture below is how it is currently laid out with the code above.
And here is how I would like it to look, instead of the tasks showing down the side, I would like them to show accross in columns with their own specific dates
Thank you in advance :)
SELECT t.sPropertyCode, sDataDate, SFirstSeen, a1.sTaskType, a2.sTaskType, a3.sTaskType
FROM tasks AS t
INNER JOIN temp AS a1 on t.sPropertyCode = a1.sPropertyCode and a1.sTaskType = 'RF'
INNER JOIN temp as a2 on t.sPropertyCode = a2.sPropertyCode and a2.sTaskType = 'IF'
INNER JOIN temp as a3 on t.sPropertyCode = a3.sPropertyCode and a3.sTaskType = 'CM'
WHERE iRemoved = 1 AND iBusinessStreamId = 9
ORDER BY sPropertyCode, sFirstSeen;
You can also user outer join if not always have all 3 tast type.
What is the difference in meaning between the CM,IF and RF columns for any row in your 5-col table ? They're always the very same value in the example you listed.