SQL - Query to split original sort - sql

I hope my title is ok as I really don’t know how to call it.
Anyway, I have a table with the following :
ID - Num (Primary Key)
Category - VarChar
Name - VarChar
DateForName - Date
Data looks like that :
1 100 111 31/12/2017
2 101 210 30/12/2017
3 100 112 29/12/2017
4 101 203 27/12/2017
5 100 117 20/12/2017
6 103 425 08/12/2017
To generate this table, I just sorted by date DESC.
Is there a way to add a new column with the order per Category like :
1 100|1
2 101|1
3 100|2
4 101|2
5 100|3
6 103|1
Max

You want analytical function row_number():
select t.*
from (select *, row_number() over (partition by Category order by date desc) Seq
from table
) t
order by id;

Yes, SQL has a couple options for you to add a column that is populated with a ranking of the rows based on the category and id columns.
If you just want to add a column to the select statement, I recommend using the RANK() function.
See more details here:
https://learn.microsoft.com/en-us/sql/t-sql/functions/rank-transact-sql?view=sql-server-2017
For your current table, try the following select statement:
SELECT
[ID],
[Category],
[Name],
[DateForName],
RANK() OVER (PARTITION BY [Category] ORDER BY [DateForName] DESC) AS [CategoryOrder]
FROM [TableName]
Alternatively, if you want to add a permanent column (aka a field) to the existing table, I recommend treating this as a calculated column. See more information here:
https://learn.microsoft.com/en-us/sql/relational-databases/tables/specify-computed-columns-in-a-table?view=sql-server-2017
Because the new column would be completely based on two pre-existing columns and only those two columns. SQL can do a great job maintaining this for you.
Hope this helps!

Related

Need help combining columns from 2 tables and keep remaining data in rows based on parameters in sql

I am needing some help with this! I have been steered toward the intersect function, but it seems limited as it only matches and returns matched values. I am trying to combine 2 tables on a common column value and return the rows based on a date parameter. Is this even possible using SQL? Thanks in advance!
My starting tables look like this:
name date doc info
janedoe 7/21 jones 47
jonwall 7/1 nick 21
name date doc info
janedoe 6/21 jones 74
jonwall 8/31 hall 22
I want to combine these rows by duplicate name. And keep the remaining data based on most recent date. so the end result should look like this.
name date doc info
janedoe 7/21 jones 47
jonwall 8/31 hall 22
Is there anyway anyone could help me on this???? I am currently using SQLExpress
WITH allRows AS (
SELECT * FROM tableA
UNION ALL
SELECT * FROM tableB
), mostRecent AS (
SELECT *,
ROW_NUMBER() OVER
(PARTITION BY name ORDER BY date DESC) as rn
FROM allRows
)
SELECT *
FROM mostRecent
WHERE rn = 1
You should have some ID column, otherwise you are risking having two person with same name.

SQL query interleaving two different statuses

I have a table testtable having fields
Id Name Status
1 John active
2 adam active
3 cristy incative
4 benjamin inactive
5 mathew active
6 thomas inactive
7 james active
I want a query that should dispaly the reuslt like
Id Name Status
1 John active
3 cristy incative
2 adam active
4 benjamin inactive
5 mathew active
6 thomas inactive
7 james active
my question is how to take records in the order of active status then inactive then active then inactive etc.. like that from this table.
This query sorts on interleaved active/inactive state:
SELECT [id],
[name],
[status]
FROM (
(
SELECT
Row_number() OVER(ORDER BY id) AS RowNo,
0 AS sorter,
[id],
[name],
[status]
FROM testtable
WHERE [status] = 'active'
)
UNION ALL
(
SELECT
Row_number() OVER(ORDER BY id) AS RowNo,
1 AS sorter,
[id],
[name],
[status]
FROM testtable
WHERE [status] = 'inactive'
)
) innerUnion
ORDER BY ( RowNo * 2 + sorter )
This approach uses an inner UNION on two SELECT statements, one which returns active rows, the other inactive rows. They both have a RowNumber generated, which is later multiplied by two to ensure it's always even. There's a sorter column that's just a bit field, and to ensure that a unique number is available for sorting: adding it to the RowNumber yields either an odd or even number depending on active/inactive state, hence allowing the results to be interleaved.
The SQL Fiddle link is here, to allow testing and manipulation:
http://sqlfiddle.com/#!3/8a8a1/11/0
In the absence of a specified DB system, I've assumed that SQL Server 2008 (or newer) is being used. An alternate row numbering system would be necessary on other DBMSes.
Finally i got the answer
SET #rank=0;
SET #rank1=0;
SELECT #rank:=#rank+1 AS rank,id,name,status FROM `testtablejohn` where status='E'
UNION
SELECT #rank1:=#rank1+1 AS rank,id,name,status FROM `testtablejohn` where status='D'
order by rank
Since you didn't post any example of what you tried so far, I will limit my answer to the general approach as well.
One approach could be to generate a row number for active rows and a row number for inactive rows. Start your numbering for active at 1 and use only odd numbers (that means increase your counter by 2 every time) and do the same thing with 2 and even numbers for the inactive rows. Put those two counters in the same column.
You will end up with a single column to easily sort on in your ORDER BY clause.
Here are some links that might be useful for you:
MySQL - Get row number on select
http://www.mysqltutorial.org/mysql-case-statement/
Just give it a go with those. If you can't make it work, then show us what you tried so far. Post some example code in the question and we might be able to guide you!

Add Ordinal/Consecutive Value for similar values in table

OK - I have a table with the following columns - what I need to do, is in instances where there is a same visit_no, I need to populate a int field with an ordinal number (priority) for each code - e.g. - so the "Priority" field is what I am looking to have populated - a new successive number for each "Code" value within the each similar "visit_no"
Visit_no Code Priority
123456 97110 1
445566 85025 1
445566 71402 2
445566 71020 3
789888 80053 1
789888 97110 2
111111 85025 1
Dense_Rank is a function which increments the rank only when the value your ordering on changes.
http://msdn.microsoft.com/en-ca/library/ms173825.aspx
Select Visit_no, Code, Priority = DENSE_RANK() OVER (Partition by Visit_No order by Code)
From YourTable

how to select one tuple in rows based on variable field value

I'm quite new into SQL and I'd like to make a SELECT statement to retrieve only the first row of a set base on a column value. I'll try to make it clearer with a table example.
Here is my table data :
chip_id | sample_id
-------------------
1 | 45
1 | 55
1 | 5986
2 | 453
2 | 12
3 | 4567
3 | 9
I'd like to have a SELECT statement that fetch the first line with chip_id=1,2,3
Like this :
chip_id | sample_id
-------------------
1 | 45 or 55 or whatever
2 | 12 or 453 ...
3 | 9 or ...
How can I do this?
Thanks
i'd probably:
set a variable =0
order your table by chip_id
read the table in row by row
if table[row]>variable, store the table[row] in a result array,increment variable
loop till done
return your result array
though depending on your DB,query and versions you'll probably get unpredictable/unreliable returns.
You can get one value using row_number():
select chip_id, sample_id
from (select chip_id, sample_id,
row_number() over (partition by chip_id order by rand()) as seqnum
) t
where seqnum = 1
This returns a random value. In SQL, tables are inherently unordered, so there is no concept of "first". You need an auto incrementing id or creation date or some way of defining "first" to get the "first".
If you have such a column, then replace rand() with the column.
Provided I understood your output, if you are using PostGreSQL 9, you can use this:
SELECT chip_id ,
string_agg(sample_id, ' or ')
FROM your_table
GROUP BY chip_id
You need to group your data with a GROUP BY query.
When you group, generally you want the max, the min, or some other values to represent your group. You can do sums, count, all kind of group operations.
For your example, you don't seem to want a specific group operation, so the query could be as simple as this one :
SELECT chip_id, MAX(sample_id)
FROM table
GROUP BY chip_id
This way you are retrieving the maximum sample_id for each of the chip_id.

In Excel how to create multiple rows from a single data row

I have an execl datasheet with data looking like this
id desc part no 1 Qty 1 part no 2 Qty 2 part no 3 Qty 3
1 PartsName 382A012-3-0 3 382A023-3 3 382A012-25 3
And need it to look like this
id desc part no Qty
1 PartsName 382A012-3-0 3
1 PartsName 382A023-3/42-0 3
1 PartsName 382A012-25/86-0 3
This from a SQL Table so I could do it in SQL if that makes it easier
Anybody any suggestions as how to best to sort this?
Simply make a UNION in the SQL
SELECT id, desc, partNo, qty FROM parts
UNION SELECT id, desc, partNo2 as partNo, qty2 as qty FROM parts
UNION SELECT id, desc, partNo3 as partNo, qty3 as qty FROM parts
ORDER BY id
If you don´t have the option of using SQL and need to use Excel. You can use the TRANSPOSE function. It is an array type function so you need to use the {}. If you haven´t used it before I recommend reading the help first. I however don´t think you can use transpose to get it exactly as you describe it. The id and desc column have to handled separately.
You need to add next formulas on a new sheet:
column A=MOD(ROW()+1,3)
it's like a skeleton :)
First row is headers
column B
=IF($A2=0,OFFSET(Sheet1!$A$1,COUNTIF($A$2:$A2,0),COLUMN()-2),B1)
autofil col C with it
column D
=OFFSET(Sheet1!$A$1,COUNTIF($A$2:$A2,0),COLUMN()+CHOOSE($A2+1,-2,0,2))
autofil col E with it
one more - your datasheet is "sheet1"