Show the incremental count for repeats in SQL SERVER - sql

Say you have a table where one column has repeat values. How can I add another column that shows how many times that value has shown up SO FAR (top-down).
Ex. You have a column say "ccode" and in ccode you have the value "R52" repeat twice. Rather than Join the final count (2), I want the first appearance of R52 to have a count=1, and the second to have a count=2, and so on...
CREATE TABLE Temp
(
ccode varchar(50),
name varchar(50),
Val1 varchar(50),
g_Name varchar(50),
ce_hybrid varchar(50)
)
INSERT INTO Temp VALUES
( 'R52' , 'adam#email.ca' , 1, 'WALT', '3P'),
( 'R52' , 'adam#email.ca' , 2 , 'KEN', '3P'),
( 'R00' , 'alison#email.ca' , 1 , 'QUIN', '3P')
SELECT ccode, name, [1_G_Name], [2_G_Name], [1_Hybrids], [2_Hybrids] FROM
(
SELECT ccode, name, col, val FROM(
SELECT *, Val1+'_G_Name' as Col, g_Name as Val FROM Temp
UNION
SELECT *, Val1+'_Hybrids' as Col, ce_hybrid as Val FROM Temp
) t
) tt
PIVOT ( max(val) for Col in ([1_G_Name], [2_G_Name], [1_Hybrids], [2_Hybrids]) ) AS pvt
For a better idea: http://sqlfiddle.com/#!18/6160d/2
I want to have a table like above, but add Val1 column afterwards (dynamically) based on the repeats SO FAR in the table (top-down).
This output (image below) is CORRECT. But say my table didn't have Val1 column:
INSERT INTO Temp VALUES
( 'R52', 'adam#email.ca', 'WALT', '3P'),
( 'R52', 'adam#email.ca', 'KEN', '3P'),
( 'R00', 'alison#email.ca', 'QUIN', '3P')
How would I add Val1 column with the (1 , 2 , 1) to based on repeat count as I mentioned
Required Output:

I got an answer thanks to an amazing senior developer at work. I would feel bad if I didn't share so:
SELECT *, rank() over (partition by ccode order by g_name) Val1 FROM Temp
Use Rank() and Partition over the table. I partitioned by ccode so any matching/duplicating will start from 1 and add 1 each time the same ccode appears in the table.
Example 1: http://sqlfiddle.com/#!18/95a0d5/6
Example 2: http://sqlfiddle.com/#!18/569d8/1
Example 3: http://sqlfiddle.com/#!18/41bf32/1
In example 3, notice how since we used order by g_name and there are 2 identical names KEN and KEN for ccode=R52, the Val1 is 2 and 2 for them and 4 next time (3 gets skipped)
I ignored the rest of the code regarding pivot since my question was more regarding this rank/partition. I'm not super familiar with it other than what was explained over a call, but hope it helps someone.
P.S. what would be a better name for this question?

Related

Add column to ensure composite key is unique

I have a table which needs to have a composite primary key based on 2 columns (Material number, Plant).
For example, this is how it is currently (note that these rows are not unique):
MATERIAL_NUMBER PLANT NUMBER
------------------ ----- ------
000000000000500672 G072 1
000000000000500672 G072 1
000000000000500672 G087 1
000000000000500672 G207 1
000000000000500672 G207 1
However, I'll need to add the additional column (NUMBER) to the composite key such that each row is unique, and it must work like this:
For each MATERIAL_NUMBER, for each PLANT, let NUMBER start at 1 and increment by 1 for each duplicate record.
This would be the desired output:
MATERIAL_NUMBER PLANT NUMBER
------------------ ----- ------
000000000000500672 G072 1
000000000000500672 G072 2
000000000000500672 G087 1
000000000000500672 G207 1
000000000000500672 G207 2
How would I go about achieving this, specifically in SQL Server?
Best Regards!
SOLVED.
See below:
SELECT MATERIAL_NUMBER, PLANT, (ROW_NUMBER() OVER (PARTITION BY MATERIAL_NUMBER, PLANT ORDER BY VALID_FROM)) as NUMBER
FROM Table_Name
Will output the table in question, with the NUMBER column properly defined
Suppose this is actual table,
create table #temp1(MATERIAL_NUMBER varchar(30),PLANT varchar(30), NUMBER int)
Suppose you want to insert only single record then,
declare #Num int
select #Num=isnull(max(number),0) from #temp1 where MATERIAL_NUMBER='000000000000500672' and PLANT='G072'
insert into #temp1 (MATERIAL_NUMBER,PLANT , NUMBER )
values ('000000000000500672','G072',#Num+1)
Suppose you want to insert bulk record.Your bulk record sample data is like
create table #temp11(MATERIAL_NUMBER varchar(30),PLANT varchar(30))
insert into #temp11 (MATERIAL_NUMBER,PLANT)values
('000000000000500672','G072')
,('000000000000500672','G072')
,('000000000000500672','G087')
,('000000000000500672','G207')
,('000000000000500672','G207')
You want to insert `#temp11` in `#temp1` maintaining number id
insert into #temp1 (MATERIAL_NUMBER,PLANT , NUMBER )
select t11.MATERIAL_NUMBER,t11.PLANT
,ROW_NUMBER()over(partition by t11.MATERIAL_NUMBER,t11.PLANT order by (select null))+isnull(maxnum,0) as Number from #temp11 t11
outer apply(select MATERIAL_NUMBER,PLANT,max(NUMBER)maxnum from #temp1 t where t.MATERIAL_NUMBER=t11.MATERIAL_NUMBER
and t.PLANT=t11.PLANT group by MATERIAL_NUMBER,PLANT) t
select * from #temp1
drop table #temp1
drop table #temp11
Main question is Why you need number column ? In mot of the cases you don't need number column,you can use ROW_NUMBER()over(partition by t11.MATERIAL_NUMBER,t11.PLANT order by (select null)) to display where you need. This will be more efficient.
Or tell the actual situation and number of rows involved where you will be needing Number column.

Merge multiple rows having some identity to a new one that have the sum of a column thats is distinct between thems

I have table like this :
id name qt
----------------
0 mm 4
1 mm 5
2 xx 8
I want update it or get new table that will produce this kind of result:
id name qt
------------------
0 mm 9 (sum of the two or multiple some identical )
1 xx 8
Including the id column will cause the GROUP BY to fail since multiple records are being summed that have different ids.
SELECT name, SUM(qt) as qt_sum
FROM table GROUP BY name
SELECT ROW_NUMBER() OVER (ORDER BY name) AS id
, name
, SUM(qt) AS qt
FROM YourTableName
GROUP BY name
ORDER BY name
I'm making the assumption that the id field doesn't actually mean anything because the id of the record xx actually changes between your two visuals. That's why I'm setting it by ROW_NUMBER() so it increments for distinct name. If this isn't the case, remove the ROW_NUMBER() expression and add id to the GROUP BY clause. This does mean that records in the name field may change depending on the number of distinct names.
If you really need and id column you could create one like this...
create table Test (id int, name varchar(10), qt int)
insert into Test values (0, 'mm', 4)
insert into Test values (1, 'mm', 5)
insert into Test values (2, 'xx', 8)
select
row_number() over (order by name) - 1
, name
, sum(qt) as qt
from Test
group by name
There may be some cases where this does not work for you, but with such limited sample data it is hard to tell.

Need Sorting With External Array or Comma Separated data

Am working with PostgreSQL 8.0.2, I have table
create table rate_date (id serial, rate_name text);
and it's data is
id rate_name
--------------
1 startRate
2 MidRate
3 xlRate
4 xxlRate
After select it will show data with default order or order by applied to any column of same table. My requirement is I have separate entity from where I will get data as (xlRate, MidRate,startRate,xxlRate) so I want to use this data to sort the select on table rate_data. I have tried for values join but it's not working and no other solution am able to think will work. If any one have idea please share detail.
Output should be
xlRate
MidRate
startRate
xxlRate
my attempt/thinking.
select id, rate_name
from rate_date r
join (
VALUES (1, 'xlRate'),(2, 'MidRate')
) as x(a,b) on x.b = c.rate_name
I am not sure if this is helpful but in Oracle you could achieve that this way:
select *
from
(
select id, rate_name,
case rate_name
when 'xlRate' then 1
when 'MidRate' then 2
when 'startRate' then 3
when 'xxlRate' then 4
else 100
end my_order
from rate_date r
)
order by my_order
May be you can do something like this in PostgreSQL?

Complicated logic of group by and partition

I have the table as per the script below.
The data that I want finally is shown in the screenshot.
The logic that is to be implemented is :
If SUM(FPR_QTY) > QPA, Use QPA without summing it up.
Else, use FPR_QTY.
Eg explanation: For the first 4 rows, TOT_FPR > QPA, so I just need 1.
While for rest 4 rows, TOT_FPR < QPA, i need to use TOT_FPR.
So, ultimately, I want 21 against each record.
Please let me know if my explanation is not clear.
create table #TEMP
(QPA int
,FPR_QTY int
, key1 varchar(2)
, key2 varchar(10)
)
insert into #TEMP values
(1,1,'K1','kk1')
,(1,0,'k1','kk1')
,(1,1,'k1','kk1')
,(1,0,'k1','kk1')
,(50,5,'k2','kk1')
,(50,5,'k2','kk1')
,(50,5,'k2','kk1')
,(50,5,'k2','kk1')
select *
,SUM(FPR_QTY) OVER (PARTITION BY key1) AS TOT_FPR
from #TEMP
Here you go...I was able to write the query within two selects. I wish I could accept my own answer as it is most simplest and will run without failure.
select * ,SUM(IIF(TOT_FPR>QPA,IIF(QPA_IND = 1,QPA,0),FPR_QTY)) OVER (PARTITION BY key2) FINAL
from
(
select *
,SUM(FPR_QTY) OVER (PARTITION BY key1) AS TOT_FPR
,ROW_NUMBER() OVER (PARTITION BY key1 order by QPA) AS QPA_IND
from #TEMP
)T

BLOB aggregation

I've got the table:
create table example (id number, image varchar2(10));
With 2 rows:
insert into example (24, 'pippo');
insert into example (35,'pluto');
The query is:
select max(case when id=24 then image end) as col1,
max(case when id=35 then image end) as col2
from example;
This works perfectly fine with column "image" as varchar2! The problem is that the column is a BLOB.
How can I produce the same output?
Take in mind that I need to pull out of the table 28 images (so 28 columns and one row).
Still not clear why you need the result in columns and not rows... perhaps you only think you do? Alex asked you the most important question: Who/what will call this and consume the results? How is the result set used in further processing? It is possible you don't actually need the results in columns.
In any case, you can use Alex's suggestion of having 28 subquery expressions. If your concern is with performance, you can first select into a CTE (a WITH clause), whose result set will have just 28 rows - and then write the subquery expressions against the CTE. Something like this:
with prep ( id, blob_col ) as (
select id, blob_col from base_table where id in (24, 35, ... )
)
select
(select blob_col from prep where id = 24) as col_1,
(select blob_col from prep where id = 35) as col_2,
...
from dual
;