Updating values of SQL column with values from the same column - sql-server-2008

If you will look at the image above. I need to update this table for the null values of the TID which is column third in the table, with the values in between two rows that actually has value.
So in the above example, I need to have rows 44-57 as 040, row 60-87 as 077 etc. One pattern that could be used is that column 2 has INS in the string, which denotes that the value in column 3 is to be changed. So I was thinking about using DATA LIKE 'INS%' in some way.
Please let me know what you think of the problem and any possible solutions.
thanks!

DECLARE #x TABLE
(Column1 INT, Column2 VARCHAR(64), TID VARCHAR(10));
INSERT #x VALUES
(42, 'INS{whatever}', '040'),
(43, 'somethingelse', '040'),
(44, 'somethingelse', NULL),
(45, 'somethingelse', NULL),
(46, 'somethingelse', NULL),
(47, 'somethingelse', NULL),
(48, 'somethingelse', NULL),
(49, 'INS{whatever}', '077'),
(50, 'somethingelse', '077'),
(51, 'somethingelse', NULL),
(52, 'somethingelse', NULL);
;WITH x AS (SELECT i = Column1, TID, rn = ROW_NUMBER() OVER (ORDER BY Column1)
FROM #x WHERE Column2 LIKE 'INS%'
),
y AS (SELECT x.TID, s = x.i, e = COALESCE(x2.i, 2000000000)
FROM x LEFT OUTER JOIN x AS x2 ON x.rn = x2.rn -1
)
UPDATE src SET TID = y.TID
FROM #x AS src
INNER JOIN y ON src.Column1 > y.s AND src.Column1 < y.e;
SELECT * FROM #x;

This assumes that:
The first two columns in your sample were duplicated (I ignore the first listed)
Col1 is a primary key
Values are to be assigned as you described based on ascending values in Col1
Performance might be bad to very bad on large tables
Performance would improve with suitable indexing (on Col1 and Col3)
Substitute in your table and column names, and check for minor typos.
UPDATE MyTable
set Col3 = mt2.Col3
from MyTable mt
inner join (-- Get the "earlier" Col3 value for each row that has no value
select t1.Col1, max(t2.Col1) EarlierValueHere
from MyTable t1
inner join MyTable t2
on t2.Col1 < t1.Col1
and t2.Col3 is not null
group by t1.Col1
where t1.Col3 is null) earlier
on earlier.Col1 = mt.Col1
inner join MyTable mt2
on mt2.Col1 = earlier.EarlierValueHere

Another query you might use:
update t set TID = X.NonNullTID
from [YourTable] t
join
(select
t1.Column1, t1.Column2, t1.TID,
(select top 1 tid from [YourTable]
where TID is not null and Column1 <= t1.Column1
order by Column1 desc) as NonNullTID
from [YourTable] t1) X
on X.Column1 = t.Column1

Related

SQL Query to get latest records for that user

I have a MySQL database and I need a little help with querying the data from the table.
// Table
id INTEGER,
column1 VARCHAR,
completiondate DATETIME
// Sample data
(101, 'a', '2020-03-20 12:00:00')
(101, 'b', '2020-03-21 12:00:00')
(101, 'c', '2020-03-22 12:00:00')
(101, 'c', '2020-03-23 12:00:00')
(101, 'd', '2020-03-24 12:00:00')
(102, 'a', '2020-03-20 12:00:00')
(102, 'b', '2020-03-21 12:00:00')
Here, I want to view all the records for that specific user and display only the latest one from the duplicates found in column1.
Expected Output for user 101:
(101, 'a', '2020-03-20 12:00:00')
(101, 'b', '2020-03-21 12:00:00')
(101, 'c', '2020-03-23 12:00:00')
(101, 'd', '2020-03-24 12:00:00')
I'm new with SQL. Would be great if anyone can provide any insight on this.
Thanks in advance!
You can filter with a subquery:
select t.*
from mytable t
where
t.id = 101
t.completiondate = (
select max(t1.completiondate)
from mytable t1
where t1.id = t.id and t1.id = t.id and t1.column1 = t.column1
)
Alternatively, in MySQL 8.0, you can use window function rank():
select *
from (
select t.*, rank() over(partition by id, column1 order by completiondate desc) rn
from mytable t
where id = 101
) t
where rn = 1
Note that, for this dataset, you could also use simple aggregation:
select id, column1, max(completiondate) completiondate
from mytable
where id = 101
group by id, column1
Here is one PHP-friendly way to do this, using joins:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT id, column1, MAX(completiondate) AS maxcompletiondate
FROM yourTable
GROUP BY id, column1
) t2
ON t1.id = t2.id AND
t1.column1 = t2.column1 AND
t1.completiondate = t2.maxcompletiondate;
I think the easiest way would be to join the tables max value to the current table somehow like this
SELECT user, `date`
FROM yourtable
INNER JOIN
(
SELECT MAX(date) AS `date`, user
FROM yourtable
GROUP BY user
) latest ON latest.`date`= yourtable.`date` AND latest.user = yourtable.user

repeating all values on all levels of a multi-level group by with aggregating function

I want get the count of colum3, but I want to group it by column1 and column2 whereby column2 has always the same (all) values of column2.
My current version: http://sqlfiddle.com/#!9/00d9d/1/0
Code:
CREATE TABLE table1
(`column1` varchar(2), `column2` varchar(2), `column3` varchar(2))
;
INSERT INTO table1
(`column1`, `column2`, `column3`)
VALUES
('aa', 'ba', 'ca'),
('aa', 'ba', 'cb'),
('aa', 'ba', 'cc'),
('aa', 'bb', 'ca'),
('aa', 'bb', 'cb'),
('aa', 'bc', 'ca'),
('aa', 'bc', 'cb'),
('aa', 'ba', 'ca'),
('ab', 'ba', 'cb'),
('ab', 'bc', 'ca')
;
My query:
SELECT
column1
,column2
,COUNT(column3)
FROM
table1
GROUP BY
column1
,column2
Result
column1 column2 COUNT(column3)
aa ba 4
aa bb 2
aa bc 2
ab ba 1
ab bc 1
Now is my question how can I ensure that in all column1 aggregations are the same values of column2? In case of the example I miss the
ab;bb;0
So I want that for every value of column1 I have the same set of values for column2. Which means in reality that a missing value gets filled up with 0 as count.
You have to first generate all allowed values (column1 x column2) and then left join this with your query. Your query will provide the count where it knows it, otherwise you will just get 0:
select base1.column1, base2.column2, ifnull(YourQuery.cnt, 0)
from (select distinct column1 from table1) as base1
cross join (select distinct column2 from table1) as base2
left join
(SELECT column1,column2,COUNT(column3) as cnt
FROM table1
GROUP BY column1,column2
) as YourQuery
on YourQuery.column1 = base1.column1 and YourQuery.column2 = base2.column2;
The idea is basically to get all the combination and use join or union to fill the gap, Here i am using union all.
SELECT
column1
,column2
,count(column3)
from (
select column1, column2, column3 from table1
union all
select column1,column2, null as column3
from (select distinct column1 from table1 ) all_c1
cross join ( select distinct column2 from table1) all_c2
)t group by column1, column2;

get rows from a table where value of field x is maximum

I have two tables myTable and myTable2 in a mysql database:
CREATE TABLE myTable (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
number INT,
version INT,
date DATE
) ENGINE MyISAM;
INSERT INTO myTable
(`id`, `number`, `version`, `date`)
VALUES
(1, '123', '1', '2016-01-12'),
(2, '123', '2', '2016-01-13'),
(3, '124', '1', '2016-01-14'),
(4, '124', '2', '2016-01-15'),
(5, '124', '3', '2016-01-16'),
(6, '125', '1', '2016-01-17')
;
CREATE TABLE myTable2 (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
myTable_id INT
) ENGINE MyISAM;
INSERT INTO myTable2
(`id`, `myTable_id`)
VALUES
(1, 1),
(2, 1),
(3, 2),
(4, 2),
(5, 3),
(6, 3),
(7, 4),
(8, 4),
(9, 4),
(10, 5),
(11, 6)
;
The field myTable2.myTable_id is a foreign key of myTable.Id.
I would like to get all the rows from myTable where myTable2.myTable_id = myTable.Id and the value of the field version in myTable is the maximum for every corresponding value for the field number in myTable.
I tried something like this:
SELECT
*
FROM
myTable,
myTable2
WHERE
myTable.version = (SELECT MAX(myTable.version) FROM myTable)
But the above query does not return the correct data. The correct query should output this:
Id number version date
2 123 2 2016-01-13
5 124 3 2016-01-16
6 125 1 2016-01-17
Please help!
One way to do this is to get the max version for each number in myTable in a derived table and join with that:
SELECT DISTINCT
m.*
FROM
myTable m
JOIN
myTable2 m2 ON m.id = m2.myTable_id
JOIN
(
SELECT number, MAX(version) AS max_version
FROM myTable
GROUP BY number
) AS derived_table
ON m.number = derived_table.number
AND m.version = derived_table.max_version
With your sample data this produces a result like this:
id number version date
6 125 1 2016-01-17
5 124 3 2016-01-16
2 123 2 2016-01-13
your Query is logically wrong. Here is the correct one
SELECT
*
FROM
myTable,
myTable2
WHERE
(myTable.version,myTable.number) in
(SELECT MAX(myTable.version),number FROM myTable group by number)
and myTable.id=myTable2.id
Here is the sqlfiddle http://sqlfiddle.com/#!9/74a67/4/0
This is the query posted for the previous edited question
SELECT * FROM myTable
inner join myTable2 on myTable.id = myTable2.mytable_id
WHERE (version, number) in
(SELECT MAX(version), number FROM myTable group by number)
Try this solution with using subquery simply as:
# Selecting desired result..
SELECT t1.id, t1.number, t1.version, t1.date
FROM myTable As t1 JOIN
# subquery to select max version and its corresponding
# number form myTable
(SELECT number, max(version) As max_ver FROM myTable
GROUP BY number
) As t2 ON t1.number = t2.number and t1.version = t2.max_ver
# Now checking for foreign key..
WHERE t1.id IN (SELECT mytable_id FROM myTable2);
Was it helpful..

Find max value from the table values

I need to write the query to find the max value from the table value.
Table structure as follows,
col col2 col3
1 a1 20150102
2 c1 20150201
3 a1 20150301
4 c1 20150101
I want the result as follows
output: table1
c1 = 20150201
a1 = 20150301
my query:
Select * from table1 where col3 = (select max(col3) from table1);
Use GROUP BY and the MAX function.
SELECT col2, MAX(col3)
FROM table1
GROUP BY col2
Output
col2 MAX(col3)
a1 20150301
c1 20150201
SQL Fiddle: http://sqlfiddle.com/#!9/73026/1/0
this way also we can do using Row_number
DECLARE #Table1 TABLE
(col int, col2 varchar(2), col3 int)
;
INSERT INTO #Table1
(col, col2, col3)
VALUES
(1, 'a1', 20150102),
(2, 'c1', 20150201),
(3, 'a1', 20150301),
(4, 'c1', 20150101)
;
select T.col2,T.col3 from #Table1 T
INNER JOIN (select RN from (select (ROW_NUMBER()OVER(PARTITION BY col2 ORDER BY col3))RN from #Table1)T GROUP BY T.RN )TT ON T.col = TT.RN
ORDER BY T.col2 DESc

MySQL: find IDs with constatnly increasing values

I have the following table:
create table my_table
(
SubjectID int,
Date Date,
Test_Value int
);
insert into my_table(SubjectID, Date, Test_Value)
values
(1, '2014-01-01', 55),
(1, '2014-01-05', 170),
(1, '2014-01-30', 160),
(2, '2014-01-02', 175),
(2, '2014-01-20', 166),
(2, '2014-01-21', 160),
(3, '2014-01-05', 70),
(3, '2014-01-07', 75),
(3, '2014-01-11', 180)
I want to find IDs with constantly increasing Test_Value over time. In this example, only SubjectID 3 satisfies that condition. Could you write the code to find this out? Thanks for your help as always.
SELECT *
FROM my_table o
WHERE NOT EXISTS (
SELECT null
FROM my_table t1
INNER JOIN my_table t2 ON t2.Date > t1.Date AND t2.Test_Value < t1.Test_Value AND t1.SubjectID = t2.SubjectID
WHERE t1.SubjectID = o.SubjectID
)
The inner query would select all the entities that DO VIOLATE the requirements: they have later dates with least values. Then the outer select entities that do not match ones from the inner query.
SQLFiddle: http://www.sqlfiddle.com/#!2/1a7ba/12
PS: presumably if you only need an id - use SELECT DISTINCT SubjectID
If the values are not monotonically increasing, then there is at least one case where adjacent values decrease. Hence, you can reduce this problem to just looking at the previous value:
select t.SubjectId
from (select t.*,
(select TestValue
from table t2
where t2.SubjectId = t.SubjectId and
t2.Date < t.Date
order by t2.Date desc
limit 1
) as prev_Test_value
from table t
) t
group by t.SubjectId
having coalesce(sum(Test_Value < prev_Test_value), 0) = 0;