I have a table named class
|Record_No [PK] | Student_No | Class_No | Seat_No |
=====================================================
|1 | 200910 | 2 | 20 |
|2 | 201234 | 2 | 13 |
|3 | 200965 | 2 | 1 |
|4 | 200920 | 2 | 8 |
|5 | 200911 | 2 | 9 |
|6 | 200955 | 1 | 10 |
|7 | 200924 | 1 | 9 |
|8 | 200922 | 1 | 1 |
|9 | 200901 | 2 | 11 |
|10 | 200902 | 2 | 18 |
is it possible to update the numbers in Seat_No in order from 1 up to the last count of Seat No where its class no is equal to 2?
the table should look like this:
|Record_No [PK] | Student_No | Class_No | Seat_No |
=====================================================
|1 | 200910 | 2 | 1 |
|2 | 201234 | 2 | 2 |
|3 | 200965 | 2 | 3 |
|4 | 200920 | 2 | 4 |
|5 | 200911 | 2 | 5 |
|6 | 200955 | 1 | 10 |
|7 | 200924 | 1 | 9 |
|8 | 200922 | 1 | 1 |
|9 | 200901 | 2 | 6 |
|10 | 200902 | 2 | 7 |
as of now, i can only achieve this by using
UPDATE class SET Seat_No = 1 WHERE Class_No = 2 AND Student_No = 200910;
UPDATE class SET Seat_No = 2 WHERE Class_No = 2 AND Student_No = 201234;
...
and so on..
How can i solve this without putting every student_no in the query? pls help.
update class
set seat_no = s.rn
from (
select
row_number() over(order by record_no) rn,
record_no
from class
where class_no = 2
) s
where class.record_no = s.record_no
If you want to update all classes:
update class
set seat_no = s.rn
from (
select
row_number() over(partition by class_no order by record_no) rn,
record_no
from class
) s
where class.record_no = s.record_no
Assuming your Record_No is 1-5 in your example, you can use it:
UPDATE class SET Seat_No = Record_No WHERE Class_No = 2
If not, it depends on your RDBMS.
Here is the postgresql approach:
UPDATE Class C
SET Seat_No = t.rn
FROM (
SELECT Record_No, ROW_NUMBER() OVER (ORDER BY Record_No) rn
FROM Class
WHERE Class_no = 2
) t
WHERE C.Record_No = t.Record_No
SQL Fiddle Demo
Related
I have the following table:
table1
----------------------------
| id | desc | dc | amount |
----------------------------
|1 | trx 1 | d | 100000 |
|2 | trx 2 | d | 500000 |
|3 | trx 3 | c | 800000 |
|4 | trx 4 | d | 100000 |
|5 | trx 5 | c | 900000 |
|6 | trx 6 | d | 700000 |
----------------------------
I need to query from table1 above to have the following output :
----------------------------------
| id | desc | d | c |
----------------------------------
|1 | trx 1 | 100000 | |
|2 | trx 2 | 500000 | |
|3 | trx 3 | | 800000 |
|4 | trx 4 | 100000 | |
|5 | trx 5 | | 900000 |
|6 | trx 6 | 700000 | |
----------------------------------
total | 1500000 | 1700000|
----------------------------------
Please advise what is the SQL command do be executed.
Try this:
SELECT
id, desc,
CASE WHEN dc = 'c' THEN amount ELSE NULL END AS c,
CASE WHEN dc = 'd' THEN amount ELSE NULL END AS d
FROM table1
I suggest you to do something like:
SELECT id, desc,
CASE WHEN dc='d' then amount else null end as d,
CASE WHEN dc='c' then amount else null end as c
FROM table1
For a set of invoice stage records by project I'm trying to determine a billing cycle using the ID of the starting invoice stage.
Here's the table - InvoiceStages
|ID| Project | StageDate | InvoiceStage | StageFlag | BillCycle |
|1 | abc123 | 10-May-18 | Finance | S | 1 |
|2 | abc123 | 15-May-18 | Review Draft | | 1 |
|4 | abc123 | 19-May-18 | Approved - NO Changes | | 1 |
|7 | abc123 | 21-May-18 | Final Invoice | E | 1 |
|9 | abc123 | 05-Jun-18 | Finance | S | 9 |
|12| abc123 | 07-Jun-18 | Review Draft | | 9 |
|15| abc123 | 09-Jun-18 | Approved - With Changes | | 9 |
|21| abc123 | 10-Jun-18 | Review Draft | | 9 |
|25| abc123 | 12-Jun-18 | Approved - NO Changes | | 9 |
|40| abc123 | 13-Jun-18 | Final Invoice | E | 9 |
|3 | xyz789 | 15-May-18 | Finance | S | 3 |
|5 | xyz789 | 19-May-18 | Review Draft | | 3 |
|6 | xyz789 | 20-May-18 | Approved - NO Changes | | 3 |
|8 | xyz789 | 22-May-18 | Final Invoice | E | 3 |
|10| xyz789 | 06-Jun-18 | Finance | S | 10 |
|11| xyz789 | 07-Jun-18 | Review Draft | | 10 |
|18| xyz789 | 09-Jun-18 | Approved - NO Changes | | 10 |
|22| xyz789 | 11-Jun-18 | Final Invoice | E | 10 |
I've looked at LAG / LEAD but wasn't sure if that would be the best option.
Select
ID
, Project
, StageDate
, InvoiceStage
, StageFlag
, ?? As BillCycle
From InvoiceStages
I expect the output for BillCycle to be the ID of the first record where StageFlag = 'S' for all records up to and including the end stage 'E'. Then the next set will start with the ID starting with 'S' again.
You can assign a group using a cumulative sum and then use a window function to get the value:
select i.*,
max(id) over (partition by project, grp) as invoice_id
from (select i.*,
sum(case when i.stageflag = 'S' then 1 else 0 end) over (partition by i.project order by i.stagedate) as grp
from InvoiceStages i
) i;
If the ids increase along with the date, you can do this without a subquery:
select i.*,
max(case when stageflag = 'S' then id end) over (partition by project) as invoice_id
from invoicestages i;
I have the following data:
Input:
----------------------------
| Id | Value|
----------------------------
| 1 |A |
| 1 |B |
| 2 |C |
| 2 |D |
| 2 |E |
| 3 |F |
----------------------------
I need to convert the results to the following:
Output (Count is based on Id)
----------------------------
| Id | Value| Count|
----------------------------
| 1 |A | 2 |
| 1 |B | 2 |
| 2 |C | 3 |
| 2 |D | 3 |
| 2 |E | 3 |
| 3 |F | 1 |
----------------------------
I am using SQL server 2008. Is it possible to write a query to do this?
If yes could anyone help me provide a SQL to obtain the above output from the input data I gave.
You are looking for COUNT OVER:
select id, value, count(*) over (partition by id)
from mytable
order by id, value;
I have a table as below:
|ID | UpDown | ContinuesUP | ContinuesDown | ContinuesStop|
|---------------------------------------------------------|
|1 | 1 | | | |
|---------------------------------------------------------|
|2 | 1 | | | |
|---------------------------------------------------------|
|3 | 1 | | | |
|---------------------------------------------------------|
|4 | -1 | | | |
|---------------------------------------------------------|
|5 | 1 | | | |
|---------------------------------------------------------|
|6 | 0 | | | |
|---------------------------------------------------------|
|7 | -1 | | | |
|---------------------------------------------------------|
|8 | -1 | | | |
|---------------------------------------------------------|
|9 | -1 | | | |
|---------------------------------------------------------|
|10 | -1 | | | |
|---------------------------------------------------------|
|11 | 0 | | | |
|---------------------------------------------------------|
|12 | 0 | | | |
|---------------------------------------------------------|
|13 | 1 | | | |
|---------------------------------------------------------|
|14 | 1 | | | |
|---------------------------------------------------------|
|15 | -1 | | | |
|---------------------------------------------------------|
I want to fast update the table to populate the three right columns based on first two columns without using Cursor or While loop.
My table has millions of rows and it takes hours when i use while loop to calculate that.
The Result Should be this:
|ID | UpDown | ContinuesUP | ContinuesDown | ContinuesStop|
|---------------------------------------------------------|
|1 | 1 | 1 | | |
|---------------------------------------------------------|
|2 | 1 | 2 | | |
|---------------------------------------------------------|
|3 | 1 | 3 | | |
|---------------------------------------------------------|
|4 | -1 | | 1 | |
|---------------------------------------------------------|
|5 | 1 | 1 | | |
|---------------------------------------------------------|
|6 | 0 | | | 1 |
|---------------------------------------------------------|
|7 | -1 | | 1 | |
|---------------------------------------------------------|
|8 | -1 | | 2 | |
|---------------------------------------------------------|
|9 | -1 | | 3 | |
|---------------------------------------------------------|
|10 | -1 | | 4 | |
|---------------------------------------------------------|
|11 | 0 | | | 1 |
|---------------------------------------------------------|
|12 | 0 | | | 2 |
|---------------------------------------------------------|
|13 | 1 | 1 | | |
|---------------------------------------------------------|
|14 | 1 | 2 | | |
|---------------------------------------------------------|
|15 | -1 | | 1 | |
|---------------------------------------------------------|
any advice and suggestions will be greatly appreciated
Thank you
using a common table expression with row_number() and a gaps and islands style solution, and another row_number()for the counting:
;with cte as (
select
id
, updown
, grp = row_number() over (order by id) - row_number() over (partition by UpDown order by id)
from t
)
select
id
, updown
, ContinuesUp = case when updown = 1 then row_number() over (partition by updown, grp order by id) end
, ContinuesDown = case when updown = -1 then row_number() over (partition by updown, grp order by id) end
, ContinuesStop = case when updown = 0 then row_number() over (partition by updown, grp order by id) end
from cte
order by id
rextester demo: http://rextester.com/KLZ58591
returns:
+----+--------+-------------+---------------+---------------+
| id | updown | ContinuesUp | ContinuesDown | ContinuesStop |
+----+--------+-------------+---------------+---------------+
| 1 | 1 | 1 | NULL | NULL |
| 2 | 1 | 2 | NULL | NULL |
| 3 | 1 | 3 | NULL | NULL |
| 4 | -1 | NULL | 1 | NULL |
| 5 | 1 | 1 | NULL | NULL |
| 6 | 0 | NULL | NULL | 1 |
| 7 | -1 | NULL | 1 | NULL |
| 8 | -1 | NULL | 2 | NULL |
| 9 | -1 | NULL | 3 | NULL |
| 10 | -1 | NULL | 4 | NULL |
| 11 | 0 | NULL | NULL | 1 |
| 12 | 0 | NULL | NULL | 2 |
| 13 | 1 | 1 | NULL | NULL |
| 14 | 1 | 2 | NULL | NULL |
| 15 | -1 | NULL | 1 | NULL |
+----+--------+-------------+---------------+---------------+
As an update:
;with cte as (
select *
, Continues = row_number() over (partition by updown, grp order by id)
from (
select *
, grp = row_number() over (order by id) - row_number() over (partition by UpDown order by id)
from t
) sub
)
update cte set
ContinuesUp = case when updown = 1 then Continues end
, ContinuesDown = case when updown = -1 then Continues end
, ContinuesStop = case when updown = 0 then Continues end
You can use this query for the update.
;WITH T AS
(
select *,
RNID = ROW_NUMBER() OVER( ORDER BY ID)
,RNUpDown = ROW_NUMBER() OVER( PARTITION BY UpDown ORDER BY ID)
from #T
)
,Y AS
(
SELECT *, RN=ROW_NUMBER() OVER(PARTITION BY UpDown,RNID-RNUpDown ORDER BY ID) FROM T
)
UPDATE Y SET
ContinuesUP = CASE WHEN UpDown = 1 THEN RN ELSE ContinuesUP END,
ContinuesDown = CASE WHEN UpDown = -1 THEN RN ELSE ContinuesUP END,
ContinuesStop = CASE WHEN UpDown = 0 THEN RN ELSE ContinuesUP END
You can use LAG analytic function to access previous row value, calculate up/down votes on a base of previous row and use it then to update like it described here or in the way like it suggested by SqlZim. Nevertheless it can be still slow for millions of records, especially if you have indexes
However, even a cursor can act fast if you use short transactions and doing this operation by relatively small batches (1000 - 10000 per one batch)
My application for learning words by reading sentences and translation of these sentences.
Each word has and belongs to many sentences and each sentence has translated sentences ('links' table) but not all translations for specific language (many english sentences are translated into japanese but do not have a translation into Russian)
I need to get words (english for example) that have sentences (english) that have translated sentences (russian)
DB:
words sentences_words sentences links(sentences_sentences)
_______________________ _____________________ __________________ _____________________________
|id |lang |word | |word_id|sentence_id| |id|lang|sentence| |sentence_1_id|sentence_2_id|
|1 |rus |Ё | | 1 | 1 | |1 |rus | ЁЖ | | 1 | 5 |
|2 |rus |Ж | | 1 | 4 | |2 |rus | ЗЖ | | 1 | 8 |
|3 |rus |З | | 2 | 1 | |3 |rus | ЙЫ | | 2 | 6 |
|4 |rus |Й | | 2 | 2 | |4 |rus | ЁЗ | | 3 | 7 |
|5 |rus |Ы | | 3 | 2 | |5 |eng | ab | | 3 | 10 |
|6 |eng |a | | 3 | 4 | |6 |eng | bc | | | |
|7 |eng |b | | 4 | 3 | |7 |eng | ca | | | |
|8 |eng |c | | 5 | 3 | |8 |jpn | | | | |
|9 |jpn | ... | | 6 | 5 | |9 |jpn | | | | |
|10 |jpn | ... | | 6 | 7 | |10|jpn | | | | |
| | | | | 7 | 5 | |11|jpn | | | | |
| | | | | 7 | 6 | |12|jpn | | | | |
| | | | | 8 | 6 | |13|jpn | | | | |
| | | | | 8 | 7 | |14|jpn | | | | |
Models:
class Word < ApplicationRecord
has_and_belongs_to_many :sentences
end
class Sentence < ApplicationRecord
has_and_belongs_to_many :words
has_and_belongs_to_many :translations,
class_name: "Sentence",
join_table: "links",
foreign_key: "sentence_1_id",
association_foreign_key: "sentence_2_id"
end
This sql works nice but I need activerecord query:
sql = "
select w.word from words w
join sentences_words sw on sw.word_id = w.id
join sentences s1 on sw.sentence_id = s1.id
join links l on l.sentence_1_id = s1.id
join sentences s2 on l.sentence_2_id = s2.id
where w.language = 'eng'
and s1.language = 'eng'
and s2.language = 'rus'
group by w.id
order by w.id"
#words = ActiveRecord::Base.connection.execute(sql)
UPD:
This code also works:
#words = Word.joins("INNER JOIN sentences_words sw ON sw.word_id = words.id
INNER JOIN sentences s1 on sw.sentence_id = s1.id
INNER JOIN links l on l.sentence_1_id = s1.id
INNER JOIN sentences s2 on l.sentence_2_id = s2.id
WHERE words.language = 'eng'
AND s1.language = 'eng'
AND s2.language = 'rus'").group(:id).order(:id)
Is it possible to do something like that? (its not works):
#words = Word.where(Sentence.where(language: 'eng').joins(:sentences).
where(sentences: {language: 'rus'})).where(language: 'eng')
or
#words = Word.joins(:sentences).joins(:translations).
where(words: {language: 'eng'}, sentences: {language: 'eng'}, translations: {language: 'rus'}
Thank you!
Hi #Dmitry you can use the nested join for this . Here is a good link for this [http://guides.rubyonrails.org/active_record_querying.html#joins]