Select first value then fill with null for unique id - sql

I'm using a Postgres database.
I've been trying to resolve this for hours and read dozens of topics with no result yet
Since I don't know how to explain my issue with words, here is what I need by example :
My query is
select distinct chiffre_affaires.contrat_pentete_id,
chiffre_affaires.chiffre_affaires_id,
chiffre_affaires.chiffre_affaires_montant_total
from chiffre_affaires;
Current output :
contrat_pentete_id
chiffre_affaires_id
chiffre_affaires_montant_total
1
1
111.7848
1
2
111.7848
1
3
111.7848
1
4
111.7848
1
5
111.7848
1
6
111.7848
2
7
90
2
8
90
2
9
90
2
10
90
Expected output :
null values can be replaced by 0, both null or 0 would work
contrat_pentete_id
chiffre_affaires_id
chiffre_affaires_montant_total
1
1
111.7848
1
2
null
1
3
null
1
4
null
1
5
null
1
6
null
2
7
90
2
8
null
2
9
null
2
10
null
Thank you in advance for any help !

Trying to understand what you want to achieve : for a group of rows with same contrat_pentete_id, ordered by chiffre_affaires_id ASC, you want to display the
chiffre_affaires_montant_total value for the first row, and NULL for the next rows. If so, you can try this :
SELECT DISTINCT
ca.contrat_pentete_id,
ca.chiffre_affaires_id,
CASE
WHEN ca.chiffre_affaires_id = first_value (ca.chiffre_affaires_id) OVER (ORDER BY ca.chiffre_affaires_id)
THEN ca.chiffre_affaires_montant_total
ELSE NULL
END AS ca.chiffre_affaires_montant_total
FROM chiffre_affaires AS ca
ORDER BY ca.contrat_pentete_id, ca.chiffre_affaires_id

Thanks to Edouard H. I finally wrote a script that did the job.
Here is the solution :
SELECT DISTINCT ca.contrat_pentete_id,
ca.chiffre_affaires_id,
ca.chiffre_affaires_annee_mois,
CASE
WHEN ca.chiffre_affaires_id =
first_value(ca.chiffre_affaires_id) OVER (PARTITION BY ca.contrat_pentete_id ORDER BY ca.chiffre_affaires_annee_mois)
THEN ca.chiffre_affaires_montant_total
END AS montant_facture
FROM chiffre_affaires AS ca
ORDER BY ca.contrat_pentete_id;

Related

Select rows based on grouped rolling sum condition in Oracle SQL

I have a table like the one below:
ID
RID
Count
1
1
1
2
1
3
3
1
5
4
1
1
5
2
1
6
2
6
7
2
3
8
2
2
9
2
4
I am trying to retrieve the rows of each RID until the rolling sum of Count is ≤ 10.
In this example I need all rows of RID = 1 and only rows 1, 2 and 3 of RID = 2.
Expected answer:
ID
RID
Count
Sum_Count
1
1
1
NULL
2
1
3
4
3
1
5
9
4
1
1
10
5
2
1
NULL
6
2
6
7
7
2
3
10
I tried with ROWNUM, inner query, etc. but nothing worked out.
Can someone please point me in the right direction?
You need to use a cumulative sum of Count by RID and then select all rows where the cumulative count is less than or equal to 10.
Try this:
select
*
from
(
select
ID,
RID,
COUNT,
sum(COUNT) over (partition by RID order by ID) as cum_count
from
my_table
)
where
cum_count <= 10

Row Number with specific window size

I want to group records by row numbers.
Like from row 1-3 in group 1 , 4-6 in group 2 , 7-9 in group 3 and so on.
Suppose below is the table structure:
Row NumberDataValue
1 A 10
2 A 5
3 A 1
4 A 33
5 A 2
6 A 127
1 B 1
2 B 0
3 B 7
4 B 7
5 B 5
6 B 8
7 B 1
8 B 0
I want a output like this:
GroupValue
1 10
1 5
1 1
2 33
2 2
2 127
1 1
1 0
1 7
2 7
2 5
2 8
3 1
3 0
I am using Oracle 11G.
I can achieve this using PL/SQL. But I have to use SQL only. As I have to use this query in a reporting tool.
If this is a duplicate question please provide the link of the answered question.
Subtract 1 from the column "RowNumber" and divide by 3.
Then use TRUNC() to get the integer part:
SELECT TRUNC(("RowNumber" - 1) / 3) + 1 "Group",
"Value"
FROM tablename
See the demo.
I would assume the name of the first column is ordering.
You can do:
select
1 + trunc(row_number() over(partition by data order by ordering) - 1) / 3,
value
from t
What you show looks like the output from something like this:
select ceil(rn/3) as grp, value
from your_table
order by rn;
Note that "row number" and "group" are reserved words/phrases which should not be used as column names. I used rn and grp instead.
I think the ceiling function is the simplest way to arrive at what you want. If you want to base it on the RowNumber column:
select ceil( RowNumber / 3.0) as grouping
If you want to calculate it yourself using row_number():
select ceil( row_number() over (order by RowNumber) / 3.0 ) as grouping

Custom aliases for all fields with GROUP BY ROLLUP

I have such tables:
Group - combination of TypeId and ZoneId
ID TypeID ZoneID
-- -- --
1 1 1
2 1 2
3 2 1
4 2 2
5 2 3
6 3 3
Object
ID GroupId
-- --
1 1
2 1
3 2
4 3
5 3
6 3
I want to build a query for grouping all these tables by TypeId and ZoneId, with number of objects which have specific combination of these field:
ResultTable
TypeId ZoneId Number of objects
-- -- --
1 1 2
1 2 1
2 1 3
2 2 1
2 3 0
3 3 0
Query for this:
SELECT
group.TypeId,
group.ZoneId,
COUNT(obj.ID) as NumberOfObjects
FROM[Group] group
JOIN[Object] obj on obj.GroupID = group.ID
GROUP BY group.TypeId, group.ZoneId ORDER BY group.TypeId
But! I want to add summarize row after each group, and make it like:
ResultTableWithSummary
TypeId ZoneId Number of objects
-- -- --
1 1 2
1 2 1
Summary (empty field) 3
2 1 3
2 2 1
2 3 0
Summary (empty field) 4
3 3 0
Summary (empty field) 0
The problem is that I can use GROUP BY ROLLUP(group.TypeId, group.ZoneId):
TypeId ZoneId Number of objects
-- -- --
1 1 2
1 2 1
1 null 3
2 1 3
2 2 1
2 3 0
2 null 4
3 3 0
3 null 0
but I cannot or don't know how to change not-null group.TypeId in summary rows with "Summary".
How can I do this?
The simplest method is coalesce(), but you need to be sure the types match:
SELECT COALESCE(CONVERT(VARCHAR(255), group.TypeId, 'Summary') as TypeId,
. . .
This is not the most general method, because it does not handle real NULL values in the GROUP BY keys. That doesn't seem to be an issue in this case. If it were, you could use a CASE expression with GROUPING().
EDIT:
For your particular variant (which I find strange), you can use:
SELECT (CASE WHEN group.TypeId IS NULL OR group.ZoneID IS NULL
THEN 'Summary' ELSE CONVERT(VARCHAR(255), group.TypeId)
END) as TypeId,
. . .
In practice, I would use something similar to the COALESCE() in both columns, so I don't lose the information on what the summary is for.

How to Subtotal Value with MAX

1.I have data as follows (just a subset - there are 20K records)
sku,id
1 1
1 2
1 2
1 2
1 3
1 4
1 1
1 2
1 3
1 4
1 4
1 4
1 5
1 6
1 6
2 1
2 1
2 2
2 3
2 3
2 3
2 4
2 4
2 5
2 5
2 6
2 7
2 1
2 2
2 3
The above values translate to
1 = 4 records
1 = 6 records
2 = 7 records
2 = 3 records
The MAX would just give me 6 for one and 7 for 2
The actual total is 1 = 10 and 2 = 10
How do I sum up to get the correct values?
You can use order by and some way of limiting rows. In standard SQL this would be:
select t.*
from t
order by id desc
fetch first 2 rows only;
However, some databases might use limit or select top or some other method.
No handling of ties here. Thousands of other questions handle this topic.
select sku, id
from (
select *, row_number() over (order by id desc) rn
from T
) t
where rn <= 2
order by rn desc;

Inserting a new indicator column to tell if a given row maximizes another column in SQL

I currently have a table in SQL that looks like this
PRODUCT_ID_1 PRODUCT_ID_2 SCORE
1 2 10
1 3 100
1 10 3000
2 10 10
3 35 100
3 2 1001
That is, PRODUCT_ID_1,PRODUCT_ID_2 is a primary key for this table.
What I would like to do is use this table to add in a row to tell whether or not the current row is the one that maximizes SCORE for a value of PRODUCT_ID_1.
In other words, what I would like to get is the following table:
PRODUCT_ID_1 PRODUCT_ID_2 SCORE IS_MAX_SCORE_FOR_ID_1
1 2 10 0
1 3 100 0
1 10 3000 1
2 10 10 1
3 35 100 0
3 2 1001 1
I am wondering how I can compute the IS_MAX_SCORE_FOR_ID_1 column and insert it into the table without having to create a new table.
You can try like this...
Select PRODUCT_ID_1, PRODUCT_ID_2 ,SCORE,
(Case when b.Score=
(Select Max(a.Score) from TableName a where a.PRODUCT_ID_1=b. PRODUCT_ID_1)
then 1 else 0 End) as IS_MAX_SCORE_FOR_ID_1
from TableName b
You can use a window function for this:
select product_id_1,
product_id_2,
score,
case
when score = max(score) over (partition by product_id_1) then 1
else 0
end as is_max_score_for_id_1
from the_table
order by product_id_1;
(The above is ANSI SQL and should run on any modern DBMS)