How to order by document chapter - sql

I need to create stored procedure for getting all the document titles from table, BUT it has to be ordered in a way that shows document chapters FIRST. I really don't know how to do this myself.
It would have to be ordered like this:
ID Chapter Description
1 0001-0299 Title
2 0001-0019 Title
3 0001 "some text"
4 0002 "some text"
.
.
. 0021-0039 Title
. 0021 "some text"
. 0022 "some text"
I think you get the point. Any chance someone can help? Thx for any help.

Perhaps you intend this:
select id, chapter, description
from t
order by left(chapter, 4),
(case when chapter like '%-%' then 1 else 2 end),
chapter;
This orders by the first four characters of the chapter, then by the chapters with the hyphens, and finally by the chapter itself. If you need for the first two values to be in the "other" order, then:
select id, chapter, description
from t
order by left(chapter, 4),
(case when chapter like '%-%' then 1 else 2 end),
(case when chapter like '%-%' then chapter end) desc,
chapter asc;

This will order by ID, then by Chapter.
IF OBJECT_ID ( 'orderedDocuments', 'P' ) IS NOT NULL
DROP PROCEDURE orderedDocuments;
GO
CREATE PROCEDURE orderedDocuments
AS
SELECT
ID, Chapter, Description
FROM
[Table Name]
ORDER BY
ID DESC
,Chapter DESC
GO

Related

SQL Count element and group on element

I am trying to create a view that counts an element and groups it based on a different element.
My table looks something like this
Source
Material
Destination
1
Src1
A123456
Dest2
2
Src1
A658979
Dest1
3
Src1
B123456
Dest1
4
Src1
B658979
Dest1
5
Src1
C123456
Dest2
Description of what I am trying to archive:
Count the materials that start with "A" as "Count Material A" and start with "B" as "Count Material B" and group by destination.
Based on the table above the result should look something like that:
Count Material A
Count Material B
Destination
1
1
2
Dest1
2
1
0
Dest2
For now I am only able to succesfully create the query for the counting part but I cannot figure out how to base the counting on the destination as well.
NOTE: I think I know how to do it when I "hardcode" the destination in the where-clause but it is expected that there will be more destinations in the future so I am trying to future-proof this solution.
Thanks for the help!
We can use conditional aggregation here:
SELECT
Destination,
COUNT(CASE WHEN Material LIKE 'A%' THEN 1 END) AS [Count Material A],
COUNT(CASE WHEN Material LIKE 'B%' THEN 1 END) AS [Count Material B]
FROM yourTable
WHERE Material LIKE 'A%' OR Material LIKE 'B%'
GROUP BY Destination;

Query to combine duplicates

I have a table that has a table with titles and description and most titles have one description but some have two or more. if a title has more than one description I need to display "Duplicate" description next to the title instead of an actual description.
Titles
______________
ID Title Description
-----------------------
1 Test ABCD
2 Test FEGH
3 Test2 AVWL
4 Test3 KLMN
5 Test3 ASDF
From the above data my query should return 3 records:
Test Duplicate
Test2 AVWL
Test3 Duplicate
I tried using
SELECT Title, CASE WHEN COUNT(Description) > 1 THEN 'Duplicate' ELSE Description END Title_desc
FROM Titles
GROUP BY Title
But it would not work, erroring out saying Description is not a part of group by. If I add Description to Group by then the query does not remove dups. Is there a way to accomplish what I need without having too many subqueries?
You can do:
select
title,
case when cnt = 1 then d else 'Duplicate' end as val
from (
select title, count(*) as cnt, max(description) as d
from t
group by title
) x
Or, without a subquery:
select title,
case when count(*) = 1 then max(description)
else 'Duplicate' end as val
from t
group by title

Oracle - concat one or more rows to different result columns

I have a table structure with data which looks like:
EventNbr | NoteNbr | NoteText
1 1 Example title
1 2 text1
1 3 text2
2 4 Example title 2
3 5 Example title 3
3 6 text3
What I need as a result is a data set which looks like
EventNbr | Title | Notes
1 Example Title text1,text2
2 Example Title2
3 Example Title3 text3
I am basically taking the minimum NoteNbr from each EventNbr and putting it in the Title column and then every other NoteNbr after the MIN would be the concatenated together with a comma in the Notes column.
What I currently have works, but only for EventNbrs which have multiple NoteNbr rows. It does not work for items which only have one NoteNbr row like EventNbr 2 above.
SELECT A.EventNbr,
MIN(A.NoteText) AS Title,
LISTAGG(A.NoteText, ',') WITHIN GROUP(ORDER BY A.NoteNbr) AS Notes
FROM EventNote A
INNER JOIN (SELECT Min(NoteNbr) Min_NoteNbr, EventNbr
FROM EventNote
GROUP BY EventNbr) B
ON (A.NoteNbr <> B.Min_NoteNbr AND A.EventNbr = B.EventNbr)
INNER JOIN EventNote C
ON (C.NoteNbr = B.Min_NoteNbr AND C.EventNbr = B.EventNbr)
GROUP BY A.EventNbr;
Result:
EventNbr | Title | Notes
1 Example Title text1,text2
3 Example Title3 text3
What do I need to add to consider scenarios where there is only one NoteNbr row?
You can use conditional aggregation and row_number():
select eventnbr,
max(case when seqnum = 1 then notetext end) as title,
listagg(case when seqnum > 1 then notetext end, ',') within group (order by seqnum) as notes
from (select en.*,
row_number() over (partition by eventnbr order by notenbr) as seqnum
from eventnote en
) en
group by eventnbr;
It may be best to run the aggregation first. This will produce almost the result you need, except it will still concatenate the title at the beginning of the notes. That can be corrected after the fact, using standard string functions substr, instr and concatenation. (The latter is needed to deal with the "exceptional case" you mentioned, when there are no actual notes.)
The advantage is that the additional operation is only performed on the output - expected to be (far?) fewer rows than the input, and the additional operation is a trivial string manipulation rather than an additional layer of sorting and partitioning.
Something like this - assuming the inputs are all in a single table (as the first part of your question implies) rather than in different tables (as your existing code suggests). I included a with clause to simulate the input table.
Note - the execution plan shows that the optimizer is smart enough to merge the subquery into the main query; the plan consists of a single SELECT operation over an aggregation (GROUP BY). all_notes is replaced with its long definition as a listagg right in the subquery, and the outer query is completely eliminated. So we have the best of both worlds: a query that can be read, but the execution is as efficient as possible.
with
eventnote(eventnbr, notenbr, notetext) as (
select 1, 1, 'Example title' from dual union all
select 1, 2, 'text1' from dual union all
select 1, 3, 'text2' from dual union all
select 2, 4, 'Example title 2' from dual union all
select 3, 5, 'Example title 3' from dual union all
select 3, 6, 'text3' from dual
)
select eventnbr, title,
substr(all_notes, instr(all_notes || ',', ',') + 1) as notes
from (
select eventnbr,
min(notetext) keep (dense_rank first order by notenbr) as title,
listagg(notetext, ',') within group (order by notenbr) as all_notes
from eventnote
group by eventnbr
)
order by eventnbr
;
EVENTNBR TITLE NOTES
-------- --------------- ------------------------------
1 Example title text1,text2
2 Example title 2
3 Example title 3 text3

SQL query ordered alphabetically

I have a table as below,
ID Description
--------------------
1 Bacteria
2 Cell Lines
3 Compounds
4 Virus
5 Others
6 AntiBody
What I want is a single SQL query, ordered alphabetically but have 'Other' (ID 5) as the last record.
Is that even possible?
Any help would greatly appreciated.
Thanks.
SELECT ID, Description
FROM YourTable
ORDER BY CASE WHEN ID = 5 THEN 1 ELSE 0 END,
Description
SELECT ID, Description
FROM yourtable
ORDER BY CASE WHEN Description = 'Others' THEN 1 ELSE 0 END, Description

SQL query for dynamic insert row

I am having data like:
ItemCode Attribute PositionID
ITEM-000032 CHESTSIZE 1
ITEM-000032 JACKETLEN 2
ITEM-000042 CHESTSIZE 1
ITEM-000042 JACKETLEN 2
**ITEM-000049 SLACKWAIST 1**
ITEM-000071 CHESTSIZE 1
ITEM-000071 JACKETLEN 2
ITEM-000074 CHESTSIZE 1
ITEM-000074 JACKETLEN 2
In above data except ITEM-000049 others are having perfect combination. so i want to create a new row for ITEM-000049
As
ITEM-000049 -- 2
to make it perfect.
Kind regards,
Om
Sounds like for each ItemCode, you are expecting 2 records, for 2 different Attributes.
So something like this is what I think you're after. Just run the SELECT part of it first without the INSERT to check it is indeed what you're after.
INSERT YourTable (ItemCode, Attribute, PositionID)
SELECT t.ItemCode, 'SECOND ATTRIBUTE', 2
FROM
(
SELECT ItemCode
FROM YourTable
GROUP BY ItemCode
HAVING COUNT(*) = 1
) t