Dynamic pivot using ANSI SQL - teradata

I have a table test123 where the data like below
create table test123
(
id varchar(3),
typ varchar(2),
val int
);
Select * from test123 order by id,typ;
id typ val
aaa 1a 10
aaa 1b 20
aaa 1c 7
aaa 2a 10
bbb 1a 5
bbb 1d 17
Now I want the output like below using ANSI SQL (which can work in Teradata)
id 1a 1b 1c 1d 2a
aaa 10 20 7 NULL 10
bbb 5 NULL NULL 17 NULL
Now the number of type can change and accordingly there will be more columns for this.
The sql below from the post Accomplish pivot in teradata sql didn't resolve my question
SELECT DISTINCT
id
-- reiteration starts here
,(SELECT SUM(val) -- assuming you have unique types for every id
FROM (SELECT DISTINCT
id
,val
,typ
FROM test123
QUALIFY (RANK() OVER(PARTITION BY typ ORDER BY id ASC))=1 -- variable 1
) AS type_1
) AS type_2 -- variable 2
-- reiteration ends here
FROM test123
I also did tried the python code given in the link Accomplish pivot in teradata sql but not getting the expected result
import pymysql
db = pymysql.connect(host="localhost", user="koushik", passwd="koushik", db="koushik")
cur = db.cursor()
for i in range(1, 251):
print(" \
,(SELECT SUM(value) -- assuming you have unique types for every id \
FROM (SELECT DISTINCT \
id \
,val \
,typ \
FROM test123 \
QUALIFY (RANK() OVER(PARTITION BY typ ORDER BY id ASC))=%d -- variable 1 \
) \
) AS type_%d -- variable 2 \
" % (i, i))
db.close()

Related

Update the missing incremental number in a data set

In one of my tables I have a column called 'Priority' which is a number starting from 1. With new data the next number will be added to the new record.
When I deleted a data from the middle there will be a gap in priority. I want to run a plsql update statement so that the mising numbers will be replaced according the priority order that I had before.
original data
Priority | user
1 | A
2 | B
3 | C
4 | D
Then I delete the record B
Priority | user
1 | A
3 | C
4 | D
After Update it should be like
Priority | user
1 | A
2 | C
3 | D
You can do this without PL/SQL:
create table demo
( priority number, username varchar2(20) );
insert all
into demo values (2, 'A')
into demo values (4, 'B')
into demo values (9, 'C')
into demo values (10, 'D')
select * from dual;
merge into demo o
using ( select row_number() over (order by priority) as new_priority
, rowid as row_id
from demo ) n
on (n.row_id = o.rowid)
when matched then update set o.priority = n.new_priority;
select * from demo;
PRIORITY USERNAME
---------- --------------------
1 A
2 B
3 C
4 D

Interactive Grid:Process with PL/SQL only that isn't based off a table

Env: Oracle APEX v5.1 with Oracle 12c Release 2
Firstly, I have created an Interactive Grid that isn't based off an underlying table as I will process this manually using PL/SQL.
I have been using the following as a guide:
https://apex.oracle.com/pls/apex/germancommunities/apexcommunity/tipp/6361/index-en.html
I basically have the following query:
select
level as id,
level as grid_row,
null as product,
null as product_item
from dual connect by level <= 1
Concentrating on just the product and product_item columns where the product_item column will be a readonly column and only the product number can be entered, I would like to achieve the following:
Product Product Item
---------- -------------
123456 123456-1
123456 123456-2
556677 556677-1
654321 654321-1
654321 654321-2
654321 654321-3
123456 123456-3
From the above, as the user types in the Product and then tabs out of the field, I would like a DA to fire that will add the sequence of "-1" to the end of that product number. Then is the user then adds another row within the IG and enters the same product number, I then want it to append "-2" to the end of it.
Only when the product changes number, I need the sequence to reset to "-1" for that new product as per 556677 and so forth.
Other scenarios that should also be taken into consideration are as follows:
From above IG, the user entered 123456 again but this should calculate that the next sequence for 123456 is "-3"
The same needs to be catered for, when a Product is removed from the IG but to always look at the max sequence number for that product.
I was thinking of possibly using APEX_COLLECTIONS as a means of storing what is currently in the grid, since no changes have been committed to the database.
Assuming you have a collection of product values (in this case, I am using the built-in SYS.ODCINUMBERLIST which is a VARRAY data type) then the SQL for your output would be:
SELECT id,
id AS grid_row,
product,
product || '-' || ROW_NUMBER() OVER ( PARTITION BY product ORDER BY id )
AS product_item
FROM (
SELECT ROWNUM AS id,
COLUMN_VALUE AS product
FROM TABLE(
SYS.ODCINUMBERLIST(
123456,
123456,
556677,
654321,
654321,
654321,
123456
)
)
)
ORDER BY id
Output:
ID | GRID_ROW | PRODUCT | PRODUCT_ITEM
-: | -------: | ------: | :-----------
1 | 1 | 123456 | 123456-1
2 | 2 | 123456 | 123456-2
3 | 3 | 556677 | 556677-1
4 | 4 | 654321 | 654321-1
5 | 5 | 654321 | 654321-2
6 | 6 | 654321 | 654321-3
7 | 7 | 123456 | 123456-3
db<>fiddle here
As you mentioned, the data you enter is not saved into the DB whilst you are inserting your products, so it is not in fact stored anywhere.
So you cannot go check if that value already exists and enter a -2 or other.
Some things to consider would be to maybe save the values into a temp table so you can then have a function go check how many product_item like 123456-% are in there and use that number +1 as your new product_item.
Or you could go the even harder way and do it all with javascript. For this you will need to somehow get all records in the IG, go through them all and see how many occurences of 123456 you have and then insert 123456-(no of occurences + 1).

SQLite query with ORDER BY limited

I have the following table:
date | id
-----------|------
unixtime_1 | 2
unixtime_1 | 7
unixtime_1 | 9
unixtime_1 | 24
unixtime_1 | 29
unixtime_1 | 21
unixtime_2 | 8
So far I get the results from such a table doing so:
SELECT date, id FROM table ORDER BY date DESC, id ASC
and I get
unixtime_1 | 2
unixtime_1 | 7
unixtime_1 | 9
unixtime_1 | 21
unixtime_1 | 24
unixtime_1 | 29
unixtime_2 | 8
I was wondering whether I could LIMIT the result so that in the range id=1-10 id=11-20 and id=21-30 I could get in the result only the record with the higher id.
So:
unixtime_1 | 9
unixtime_1 | 29
Since for id range=11-20 there isn't any record, it should be skip the range.
The range now are 1-10, 11-20, 21-30 but are custom ranges set by me according to the user request so I should be able to change them.
Is that possible via query?
Thank you
Your latest requirement should be possible to achieve merely by grouping by the date and (id - 1) / <some_number>, where in your example <some_number> would be 10.
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT date, (id - 1) / 10 AS id_grp, MAX(id) AS max_id
FROM yourTable
GROUP BY date, (id - 1) / 10
) t2
ON t1.date = t2.date AND t1.id = t2.max_id
ORDER BY
t1.date, t1.id;
You may choose any range you want 1 - num by simply replacing 10 in my query with the end of the range.
If i did understand correctly and if your range is id=1-3
you could simply do:
SELECT id, date FROM table WHERE id>=1 AND id<=3 ORDER by id DESC, date DESC limit 1;
this will give you only 1 record with the highest id in the range id=1-3.
you can store it and perform another query for another range and combine them later
Try this:
SELECT date, MAX(ID) FROM table GROUP BY date

Printing SSRS report to label printer x times

I am sorry if this is a duplicate question and please point me to the answer if it is.
Here is my situation:
I have an ASP.NET web forms site that uses SQL server database as its data source. The end user wants to print labels to a Zebra label printer. (Old printer Zebra 110XiIIIPlus-200dpi) I can install this printer on the end users system or it can run from the web server, doesn't matter it is a network printer.
I can retrieve the data from the database ok. My problem starts when I need to print. Lets say that I have four parts, p1 p2 p3 & p4. All the labels have the same format:
Job #, Mark #, Customer, Width(in), Length(in) (which all come from the SQL DB)
The only field that is pulled in query and not printed is the qty. Mark # is the part number (Don't know why it isn't just called part #). Now lets say that p1 has a qty of 12, p2 has a qty of 25, p3 has a qty 321, and p4 has a qty of 35.
When it prints I need to send 12 "copies" of the label for p1, 25 "copies" for p2, 321 "copies for p3, and 35 "copies" for p4.
How do I send 12 labels for p1 to be printed, then use the next record's data and send 24 labels etc. etc.?
I do not have any code for printing yet because i can not figure out how to do this!! Does anyone know of a way that I can do it.
I did find one article here on SO: Print a report Multiple times, (SSRS reporting services) but I am not sure how to make it work, if it even can) for what I need.
One last note I am using VB.Net in the code behind if it makes a difference.
Any help is very much appreciated!
I had to do the exact same thing, the solution I came up with was to loop though the select and union the same select by the number of items in the Quantity. By doing this you should get 12 rows for the P1 since that that is the quantity of boxes, all the data should be the same except for Page# that should auto increase by 1 until the end of the quantity.
Results would be something like:
Job# | Mark# | Quantity | Page
------------------------------
1 | P1 | 12 | 1
1 | P1 | 12 | 2
1 | P1 | 12 | 3
1 | P1 | 12 | 4
.....
1 | P1 | 12 | 12
Then you would group on Mark# and Page and Create a Page break between each instance of a group, this will make it so you get the number of pages based on the quantity.
Thanks to the help of SO user newGuy I was able to figure out how to do this. Here is the solution that I cam up with that works.
--Drop Temp tables if exists
If OBJECT_ID('tempdb..#Labels') Is Not Null Drop Table #Labels
If OBJECT_ID('tempdb..#Pieces') Is Not Null Drop Table #Pieces
--Declare variables
Declare #MarkNumber varchar(10)
Declare #Qty int
Declare #RowCount int = 0
Create Table #Labels
(
vjobnum varchar(12),
marknumber varchar(25),
customer varchar(25),
pwidth decimal(18,4),
plength decimal(18,4)
)
Create Table #Pieces
(
marknum varchar(25),
totqty int,
customer varchar(50),
jobnum varchar(12),
plength decimal(18,4),
pwidth decimal(18,4)
)
Insert Into #Pieces(marknum, totqty, customer, jobnum, plength, pwidth)
Select od.marknum, od.qty, oh.customer, oh.van_job_num, od.bbin, od.cbin From tbl_order_detail od Join tbl_order_head oh On oh.ordernum = od.ordernum Where od.ordernum = (Select Distinct ordernum From tbl_BearingBarRpt)
Set #RowCount = (Select COUNT(*) From #Pieces)
While #RowCount > 0 --Exists (Select marknum From #piecelabels)
Begin
Select #MarkNumber = (Select a.marknum From (Select ROW_NUMBER() OVER (Order By marknum) as RowNumbers, *From #Pieces) a Where a.RowNumbers = #RowCount)
Select #Qty = (Select totqty From #Pieces Where marknum = #MarkNumber)
While #Qty > 0
Begin
Insert Into #Labels(vjobnum, marknumber, customer, pwidth, plength)
Select pc.jobnum, pc.marknum, pc.customer, pwidth, plength
From #Pieces pc
Where pc.marknum = #MarkNumber
--Decrement the Qty counter
Set #Qty = #Qty - 1
End
Set #RowCount = #RowCount - 1
End
It may not be the best but it definitely works!

Table name in another table using PostgreSQL

I have one table in which I have name of all the tables.
Table
ID | Name | table_name|
1 | A | abc
2 | B | xyz
3 | C | 123
Now I have tables abc, xyz and 123 on the basis of name I want to get the table name and then from that table I want it complete data
SELECT *
FROM (SELECT table_name FROM Table 1 WHERE Table1.Name = 'A')
This query is not working in PostgreSQL
Please try after modifying the query as follows:
SELECT *
FROM (SELECT table_name FROM Table 1 WHERE Table1.Name = 'A') As TblName

Resources