Insert rows based on number of distinct values in another table in SQL - sql

I have a table with PO#,Days_to_travel, and Days_warehouse fields. I take the distinct Days_in_warehouse values in the table and insert them into a temp table. I want a script that will insert all of the values in the Days_in_warehouse field from the temp table into the Days_in_warehouse_batch row in table 1 by PO# duplicating the PO records until all of the POs have a record per distinct value.
Example:
Temp table: (Contains only one field with all distinct values in table 1)
Days_in_warehouse
20
30
40
Table 1 :
PO# Days_to_travel Days_in_warehouse Days_in_warehouse_batch
1 10 20
2 5 30
3 7 40
Updated Table 1:
PO# Days_to_travel Days_in_warehouse Days_in_warehouse_batch
1 10 20 20
1 10 20 30
1 10 20 40
2 5 30 20
2 5 30 30
2 5 30 40
3 7 40 20
3 7 40 30
3 7 40 40
Any ideas as to how can I update Table 1 to see desired results?

One more way without a TEMP table and DELETE.
UPDATE T SET [Days_in_warehouse_batch] = [Days_in_warehouse];
INSERT INTO T ([PO], [Days_to_travel],
[Days_in_warehouse], [Days_in_warehouse_batch])
SELECT T.PO,
T.Days_to_travel,
T.Days_in_warehouse,
DAYS_Table.Days_in_warehouse
FROM T
CROSS JOIN
(SELECT DISTINCT Days_in_warehouse FROM T) as DAYS_Table
WHERE T.Days_in_warehouse <> DAYS_Table.Days_in_warehouse;
SQLFiddle demo

I would suggest the following:
insert into table1(PO#, Days_to_travel, Days_in_warehouse, Days_in_warehouse_batch)
select PO#, Days_to_travel, Days_in_warehouse, Days_in_warehouse
from table1 cross join
(select 20 as Days_in_warehouse union all select 30 union all select 40) var
where Days_in_warehouse_batch is null;
delete from table1
where Days_in_warehouse_batch is null;

What you're looking for is the cartesian product between your two tables.
select t1.po, t1.daystotravel, t1.daysinwarehouse, temp.daysinwarehousebatch
from table1 t1, temp
The easiest way I can think of updating table1 with these values is to insert them, and then delete the originals.
insert into table1
select t1.po, t1.daystotravel, t1.daysinwarehouse, temp.daysinwarehousebatch
from table1 t1, temp
And then delete the originals:
delete from table1 where daysinwarehousebatch is null
SQL Fiddle Demo

Related

Set Insert trigger to store max value in another column

This is what my table looks like:
student_id
subject_id
total
max
101
1
6
102
2
5
103
1
9
101
1
10
103
2
2
104
1
7
I want the "max" column to be automatically populated when the total is inserted.
Expected Output:
student_id
subject_id
total
max
101
1
10
10
102
2
5
7
103
1
9
10
101
1
8
10
103
2
2
7
104
1
7
10
I will like to create a trigger for this.
This is my SELECT statement which works fine but how do I put it in a trigger?
WITH CTE AS (SELECT `subject_id`,MAX(`total`) AS MaxTotal
FROM results
GROUP BY `subject_id`
)
SELECT results.*,CTE.MaxTotal
FROM results
JOIN CTE ON results.`subject_id` = CTE.`subject_id`;
I did this but I got a plethora of errors
CREATE TRIGGER `max_score_before_INSERT` BEFORE INSERT ON `results`
FOR EACH ROW
SET NEW.max = (WITH CTE AS (SELECT `subject_id`,MAX(`NEW.total`) AS MaxTotal
FROM results
GROUP BY `subject_id`
)
SELECT results.*,CTE.MaxTotal
FROM results
JOIN CTE ON results.`subject_id` = CTE.`subject_id`
);
You can't reference "new" inside a BEFORE trigger type. You may want to first
insert the row, then update the column with an AFTER trigger type:
CREATE TRIGGER `max_score_before_INSERT` AFTER INSERT ON `results`
FOR EACH ROW
UPDATE <your_table_name>
INNER JOIN (SELECT subject_id,
MAX(total) AS total_max
FROM <your_table_name>
GROUP BY subject_id) cte
ON <your_table_name>.subject_id = cte.subject_id
SET <your_table_name>.max = cte.total_max;
Note that this approach will update the previous columns too, as if you insert a new field that becomes the max, you may want to update the already existing rows too. If not, then you can use a condition inside the UPDATE statement:
CREATE TRIGGER `max_score_before_INSERT` AFTER INSERT ON `results`
FOR EACH ROW
UPDATE <your_table_name>
INNER JOIN (SELECT subject_id,
MAX(total) AS total_max
FROM <your_table_name>
GROUP BY subject_id) cte
ON <your_table_name>.subject_id = cte.subject_id
SET <your_table_name>.max = cte.total_max;
WHERE <your_table_name>.student_id = NEW.student_id
AND <your_table_name>.subject_id = NEW.subject_id;

To get length of all columns from a table which are greater than 10

length of all columns which are greater then 10, for suppose if we have 20 columns in table 1 and 2 with 50 rows, in 50 rows for only 10 rows 5 columns are having length greater then 10 , i want that 10 rows list with that 5 columns
select * from table1 t1
join table2 t2 on t1.id=t2.id
select * from table1
where length(col1) > 10 or length(col2) > 10 ...etc.
You have not provided a complete example as requested, so this is all I can think of for now.

Append 2 tables with identical fields

I have 2 tables with identical columns. Is there a way I can append them together. For example if my tables are:
Table 1:
ID Age
1 21
2 26
3 19
4 40
Table 2:
ID Age
6 29
8 40
10 35
I'd like the desired output to be:
ID Age
1 21
2 26
3 19
4 40
6 29
8 40
10 35
Is there a way I can append these 2 tables. Being new to SQL I tried using insert but couldn't do much about it.
Would be great if some one can help out
You can use a UNION ALL query:
SELECT ID, Age
FROM table1
UNION ALL
SELECT ID, Age
FROM table2
This will return all rows from each table in a single result. Here is a demo.
Use Union rather Union All if you want unique values based on two tables.
https://stackoverflow.com/a/49928/2745294
SELECT ID, Age
FROM table1
UNION
SELECT ID, Age
FROM table2

Select Previous Record in SQL Server 2008

Here's the case: I have one table myTable which contains 3 columns:
ID int, identity
Group varchar(2), not null
value decimal(18,0), not null
Table looks like this:
ID GROUP VALUE Prev_Value Result
------------------------------------------
1 A 20 0 20
2 A 30 20 10
3 A 35 30 5
4 B 100 0 100
5 B 150 100 50
6 B 300 200 100
7 C 40 0 40
8 C 60 40 20
9 A 50 35 15
10 A 70 50 20
Prev_Value and Result columns should be custom columns. I need to make it on view. Anyone can help? please... Thank you so much.
The gist of what you need to do here is to join the table to itself, where part of the join condition is that the value column of the joined copy of the table is less than value column of the original. Then you can group by the columns from the original table and select the max value from the joined table to get your results:
SELECT t1.id, t1.[Group], t1.Value
, coalesce(MAX(t2.Value),0) As Prev_Value
, t1.Value - coalesce(MAX(t2.Value),0) As Result
FROM MyTable t1
LEFT JOIN MyTable t2 ON t2.[Group] = t1.[Group] and t2.Value < t1.Value
GROUP BY t1.id, t1.[Group], t1.Value
Once you can update to Sql Server 2012 you'll also be able to take advantage of the new LAG keyword.

Select all items with sum of fields in specified range

I have simple table:
file_size file_id file_time
1 1 19
2 2 20
3 3 21
4 4 22
5 5 23
I want to find such item that all items with less file_time has the sum of file_size in predefined range.
I written next query:
SELECT * FROM test_table AS D0 WHERE
(SELECT TOTAL(file_size) FROM test_table AS D1 WHERE
D1.file_time <= D0.file_time ORDER BY file_id)
BETWEEN 1 AND 9
This query get correct results:
1 1 19
2 2 20
3 3 21
But this query does not work if needed items has the same file_time field:
file_size file_id file_time
1 1 20
2 2 20
3 3 20
4 4 20
5 5 20
The desired result for this data is:
1 1 20
2 2 20
3 3 20
The file_id field is unique.
What is wrong in my SQL-query?
The code to create test table:
CREATE TABLE test_table (file_size INT, file_id INT, file_time INT)
INSERT INTO test_table VALUES(1,1,20)
INSERT INTO test_table VALUES(2,2,20)
INSERT INTO test_table VALUES(3,3,20)
INSERT INTO test_table VALUES(4,4,20)
INSERT INTO test_table VALUES(5,5,20)
You shouldn't consider file_time as a single column in your query, since you want to consider the column file_id either. You should use the pairs of file_time and file_id and you should compare them lexicographically as follows:
SELECT *
FROM test_table AS D0
WHERE (
SELECT TOTAL( file_size )
FROM test_table AS D1
WHERE D1.file_time < D0.file_time
OR (
D1.file_time = D0.file_time
AND D1.file_id <= D0.file_id
)
ORDER BY file_time, file_id DESC
)
BETWEEN 1
AND 9
Not sure if I understood but I think
-- sum of file sizes between 1 and 7 with the lowest time
SELECT SUM(test.file_size) AS sum_file_size, test.file_time
FROM test
WHERE (test.file_time = (SELECT TOP 1 test.file_time
FROM test
ORDER BY file_time))
AND (test.file_size BETWEEN 1 AND 9)
GROUP BY test.file_time;
-- sum of file sizes per time `group`
SELECT SUM(test.file_size) AS sum_file_size, test.file_time,
FROM test
WHERE (test.file_size BETWEEN 1 AND 7)
GROUP BY test.file_time
ORDER BY test.file_time;