How to index two columns automatically in sql - sql

I have a table in sql having two fields 'JOB_NUMBER' 'SRno', the relation between the two is such that each job number has many SRNO starting from 1,2,3 and so on,every new Job number has to have a SR no starting form 1,
so my ideal table should some what look like this:
JOB_NUMBER SRno
1 1
1 2
1 3
2 1
2 2
3 1 and so on.......
What I want to do is to achive this indexing in sql itself ,can I do this ,is so how?

If there is another column on the table that is something like a timestamp (e.g. time submitted), then you can do something like:
select job_number,
row_number() over (partition by job_number order by time_submitted asc) as SRno
from tbl
You could make that into a view and you're good to go. Keep in mind that this will be sensitive to data modifications (i.e. if someone inserts a row between two other rows, the rows after the inserted one will be "renumbered"). Also keep in mind that this won't store the SRno on the table; it has to be calculated dynamically.

You mean auto-numbering (indexing is something different in DBMS's). It can be achieved using a trigger. But that's DBMS-specific issue. Check if your database supports triggers.

Are you looking for something like this..
select JOB_NUMBER,ROW_NUMBER() over(partition by JOB_NUMBER order by JOB_NUMBER)
as SRno from table_jobs

Related

How to create new count column based on adjacent combinations in existing table

I have a simple table I've already built in BigQuery and all I want to do is what feels like a simple count of the number of times the combination of the person_id and the specific activity in the activity column has appeared in that table and create as a new column with a value/count of the adjacent combination in every row: 'combination_count' There are thousands of rows in the table so it's no good creating a filter or wheres etc.
It feels really simple but it's driving me mad. I've tried using counts and partitions but it doesn't work for me.
desired result:
person_id
activity
combination_count
1234
activity_1
1
1234
activity_1
2
1234
activity_2
1
5678
activity_1
1
and so on...
You can use row_number():
select t.*,
row_number() over (partition by person_id, activity order by person_id)
from t;

Select 1 record from each of 2 duplicate records

I have a messaging application which regularly inserts duplicate messages in BigQuery. The table name is 'metrics' and it has the following fields:
The Row column is a bigquery ROW_NUMBER() which is not part of the metrics table. All the other columns except batch_id form 2 duplicate rows for each message_id. You can see that message_id is repeated twice, and for each insertion 1 different batch_id is created.
I want the output like this, only 3 rows should be in the select result with 3 different message_id instead of the 6 rows i get here. It would be better if the row which had been inserted first among the duplicates for each message id would be selected(as the start_time and end_time is same for the duplicates i am not sure how to find that). I am new to Bigquery seen some examples in sql but not in Bigquery so any help is appreciated
Thanks for your help.
This deduping process becomes part of your business logic, so pick one method and stay consistent. I would do something like this:
with data as (
select
*,
row_number() over(partition by message_id order by batch_id asc) as rn
from `project.dataset.table`
)
select * from data where rn = 1
This query selects the row that has the "minimum" batch_id for each message_id. Your batch_id seem random/hashed (and not necessarily in a specific order), so this might or might work for your purposes, but it should reproduce the same results everytime (unless a 3rd record shows up, then it could begin to vary).

Getting the last record in SQL in WHERE condition

i have loanTable that contain two field loan_id and status
loan_id status
==============
1 0
2 9
1 6
5 3
4 5
1 4 <-- How do I select this??
4 6
In this Situation i need to show the last Status of loan_id 1 i.e is status 4. Can please help me in this query.
Since the 'last' row for ID 1 is neither the minimum nor the maximum, you are living in a state of mild confusion. Rows in a table have no order. So, you should be providing another column, possibly the date/time when each row is inserted, to provide the sequencing of the data. Another option could be a separate, automatically incremented column which records the sequence in which the rows are inserted. Then the query can be written.
If the extra column is called status_id, then you could write:
SELECT L1.*
FROM LoanTable AS L1
WHERE L1.Status_ID = (SELECT MAX(Status_ID)
FROM LoanTable AS L2
WHERE L2.Loan_ID = 1);
(The table aliases L1 and L2 could be omitted without confusing the DBMS or experienced SQL programmers.)
As it stands, there is no reliable way of knowing which is the last row, so your query is unanswerable.
Does your table happen to have a primary id or a timestamp? If not then what you want is not really possible.
If yes then:
SELECT TOP 1 status
FROM loanTable
WHERE loan_id = 1
ORDER BY primaryId DESC
-- or
-- ORDER BY yourTimestamp DESC
I assume that with "last status" you mean the record that was inserted most recently? AFAIK there is no way to make such a query unless you add timestamp into your table where you store the date and time when the record was added. RDBMS don't keep any internal order of the records.
But if last = last inserted, that's not possible for current schema, until a PK addition:
select top 1 status, loan_id
from loanTable
where loan_id = 1
order by id desc -- PK
Use a data reader. When it exits the while loop it will be on the last row. As the other posters stated unless you put a sort on the query, the row order could change. Even if there is a clustered index on the table it might not return the rows in that order (without a sort on the clustered index).
SqlDataReader rdr = SQLcmd.ExecuteReader();
while (rdr.Read())
{
}
string lastVal = rdr[0].ToString()
rdr.Close();
You could also use a ROW_NUMBER() but that requires a sort and you cannot use ROW_NUMBER() directly in the Where. But you can fool it by creating a derived table. The rdr solution above is faster.
In oracle database this is very simple.
select * from (select * from loanTable order by rownum desc) where rownum=1
Hi if this has not been solved yet.
To get the last record for any field from a table the easiest way would be to add an ID to each record say pID. Also say that in your table you would like to hhet the last record for each 'Name', run the simple query
SELECT Name, MAX(pID) as LastID
INTO [TableName]
FROM [YourTableName]
GROUP BY [Name]/[Any other field you would like your last records to appear by]
You should now have a table containing the Names in one column and the last available ID for that Name.
Now you can use a join to get the other details from your primary table, say this is some price or date then run the following:
SELECT a.*,b.Price/b.date/b.[Whatever other field you want]
FROM [TableName] a LEFT JOIN [YourTableName]
ON a.Name = b.Name and a.LastID = b.pID
This should then give you the last records for each Name, for the first record run the same queries as above just replace the Max by Min above.
This should be easy to follow and should run quicker as well
If you don't have any identifying columns you could use to get the insert order. You can always do it like this. But it's hacky, and not very pretty.
select
t.row1,
t.row2,
ROW_NUMBER() OVER (ORDER BY t.[count]) AS rownum from (
select
tab.row1,
tab.row2,
1 as [count]
from table tab) t
So basically you get the 'natural order' if you can call it that, and add some column with all the same data. This can be used to sort by the 'natural order', giving you an opportunity to place a row number column on the next query.
Personally, if the system you are using hasn't got a time stamp/identity column, and the current users are using the 'natural order', I would quickly add a column and use this query to create some sort of time stamp/incremental key. Rather than risking having some automation mechanism change the 'natural order', breaking the data needed.
I think this code may help you:
WITH cte_Loans
AS
(
SELECT LoanID
,[Status]
,ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM LoanTable
)
SELECT LoanID
,[Status]
FROM LoanTable L1
WHERE RN = ( SELECT max(RN)
FROM LoanTable L2
WHERE L2.LoanID = L1.LoanID)

Converting Rows to Columns in SQL SERVER 2008

In SQL Server 2008,
I have a table for tracking the status history of actions (STATUS_HISTORY) that has three columns ([ACTION_ID],[STATUS],[STATUS_DATE]).
Each ACTION_ID can have a variable number of statuses and status dates.
I need to convert these rows into columns that preferably look something like this:
[ACTION_ID], [STATUS_1], [STATUS_2], [STATUS_3], [DATE_1], [DATE_2], [DATE_3]
Where the total number of status columns and date columns is unknown, and - of course - DATE_1 correlates to STATUS_1, etc. And I'd like for the status to be in chronological order (STATUS_1 has the earliest date, etc.)
My reason for doing this is so I can put the 10 most recent Statuses on a report in an Access ADP, along with other information for each action. Using a subreport with each status in a new row would cause the report to be far too large.
Is there a way to do this using PIVOT? I don't want to use the date or the status as a column heading.
Is it possible at all?
I have no idea where to even begin. It's making my head hurt.
Let us suppose for brevity that you only want 3 most recent statuses for each action_id (like in your example).
Then this query using CTE should do the job:
WITH rownrs AS
(
SELECT
action_id
,status
,status_date
,ROW_NUMBER() OVER (PARTITION BY action_id ORDER BY status_date DESC) AS rownr
FROM
status_history
)
SELECT
s1.action_id AS action_id
,s1.status AS status_1
,s2.status AS status_2
,s3.status AS status_3
,s1.status_date AS date_1
,s2.status_date AS date_2
,s3.status_date AS date_3
FROM
(SELECT * FROM rownrs WHERE rownr=1) AS s1
LEFT JOIN
(SELECT * FROM rownrs WHERE rownr=2) AS s2
ON s1.action_id = s2.action_id
LEFT JOIN
(SELECT * FROM rownrs WHERE rownr=3) AS s3
ON s1.action_id = s3.action_id
NULL values will appear in the rows where the action_id has less then 3 status-es.
I haven't had to do it with two columns, but a PIVOT sounds like what you should try. I've done this in the past with dates in a result set where I needed the date in each row be turned into the columns at the top.
http://msdn.microsoft.com/en-us/library/ms177410.aspx
I sympathize with the headache from trying to design and visualize it, but the best thing to do is try getting it working with one of the columns and then go from there. It helps once you start playing with it.

SQL Order By list of strings?

I wish to do a select on a table and order the results by a certain keyword or list of keywords. For example I have a table like so:
ID Code
1 Health
2 Freeze
3 Phone
4 Phone
5 Health
6 Hot
so rather than just do a simple Order By asc/desc I'd like to order by Health, Phone, Freeze, Hot. Is this possible?
Try using this:
select * from table
order by FIELD(Code, 'Health', 'Phone', 'Freeze', 'Hot')
Here's a horrible hack:
select * from table
order by (
case Code
when 'Health' then 0
when 'Phone' then 1
when 'Freeze' then 2
when 'Hot' then 3
end
)
You can join with the Keywords table, and include a sequence column, and ORDER BY Keyword.Sequence.
Example your keywords table looks like this:
ID Code Sequence
1 Health 1
2 Freeze 3
3 Phone 2
4 Hot 4
Then you can join.
SELECT *
FROM MyTable INNER JOIN
Keywords ON Keywords.ID = MyTable.KeywordID
ORDER BY Keywords.Sequence
Hope this gives you the idea.
Nowadays MySQL has a function called find_in_set()
Use it like this:
select * from table
order by find_in_set(Code,'Health','Phone','Freeze','Hot')
Is this just a one off ORDER BY or something that you're going to want to do often and on more values than specified here?
The order that you have given is arbitrary, therefore an identifier needs to be given to achieve what you want
SELECT
ID,
Code,
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END As OrderBy
FROM Table
ORDER BY
OrderBy
Or
SELECT
ID,
Code
FROM Table
ORDER BY
CASE Code
WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 3
WHEN 'Hot' THEN 4
END
(I'm not familiar with MySQL but the above would work in SQL Server. The syntax for MySQL won't be too different)
If you're likely to want to do this often, then create an OrderBy column on the table or create an OrderBy table with a FK link to this table and specify an OrderBy numerical field in that.
Hi this is a SQL Server query but I am sure you can do this in MySQL as well:
SELECT ID, Code
FROM x
ORDER BY
CASE Code WHEN 'Health' THEN 1
WHEN 'Phone' THEN 2
WHEN 'Freeze' THEN 4
WHEN 'Hot' THEN 5
ELSE 6 END ASC
, Code ASC
Couple options:
Add OrderCode column with numerical
desired order
Add a table with FK to this table ID
and OrderCode
Yes join your results to your code table and then order by code.CodeOrder
EDIT: Explaing the use of the code table...
Create a separate table of Codes (CodeId, Code, CodeOrder) and join to this and order by CodeOrder. This is nicer than doing the order by (case...) hack suggested since you can easily change the codes and the orders.