How can combine this two tables and create a new table? - sql

How to combine two tables and create a new table
first table :
ExitDate | fullname | outputnumber
------------------------------------------------
2012/01/01 a 10
2012/01/06 b 2
2012/01/08 c 3
2012/01/12 d 4
second table
inputnumber | date
-------------------------------
100 2012/01/05
150 2012/01/07
200 2012/01/10
the answer table
ExitDate | fullname | outputnumber | inputnumber | date
-------------------------------------------------------------------------------
2012/01/01 a 10 - -
- - - 100 2012/01/05
2012/01/06 b 2 - -
- - - 150 2012/01/07
2012/01/08 c 3 - -
- - - 200 2012/01/10
2012/01/12 d 4 - -
note : the date and location is important and i using sql server

If I correctly understand, you need union all. Something like this :
select * from (
select ExitDate, fullname, outputnumber, NUll as inputnumber, NUll as [date] from first_table
union all
select NUll as ExitDate, NUll as fullname, NUll as outputnumber, inputnumber, [date] from second_table
) t
order by coalesce(ExitDate, [date])
Then entire result is sorted by combined dates from ExitDate and date columns
rextester demo

I think you can have a better table like this:
select *
from (
select fullname, 0 as io, outputnumber as number, ExitDate as date
from table1
union all
select '-', 1, inputnumber, date) t
order by date, io;
fullname | io | number | date
---------+----+--------+-------------
a | 0 | 10 | 2012/01/01
- | 1 | 100 | 2012/01/05
b | 0 | 2 | 2012/01/06
- | 1 | 150 | 2012/01/07
c | 0 | 3 | 2012/01/08
- | 1 | 200 | 2012/01/10
d | 0 | 4 | 2012/01/12

You can get the exact output you want using full outer join:
select t1.*, t2.*
from t1 full outer join
t2
on 1 = 0
order by coalesce(t1.exitdate, t2.date);

Related

SQL / HiveQL to assign values to buckets based on a table

I have a table "bucket" containing minimum int values for buckets, like this
min_value bucket_id
--------- ---------
0 1
12345 2
67890 3
i.e. any value >= 0 and < 12345 belongs in bucket 1, ..., any value >= 67890 belongs in bucket 3.
and a table of int values "value" like this:
id value
-- -----
11 10
22 20000
33 80000
I would like to figure out which bucket each value belongs to. So
select id, bucket_id
from (some join, or whatever, of bucket and value)
gives me
id bucket_id
-- ---------
11 1
22 2
33 3
I am trying to implement this in HiveQL. Any ideas?
I assumed that the condition for the bucket with largest min_value is min_value <= value (since there is no bucket with larger min_value) and I also assumed integer type for column value of table value and column min_value of table bucket (that's important because the query uses comparison which works differently in case of string type so you need to do typecasting for string).
The following query works for non-negative value of table value, in case of negative values involved, you have to replace
max(if(a.value >= b.min_value, b.min_value, 0))
with
max(if(a.value >= b.min_value, b.min_value, <minimum possible value that "value" field may have>)):
select
c.id,
if(d.bucket_id is null, 'not in bucket', d.bucket_id)
from
(
select
a.id,
max(if(a.value >= b.min_value, b.min_value, 0)) as bucket_min_value
from
value a
left join
bucket b
group by a.id
)
c
left join
bucket d
on c.bucket_min_value = d.min_value
;
You can use window functions to define ranges for the bucket ids and then join the bucket table. Check this out.
> select * from bucket;
+-------------------+-------------------+--+
| bucket.min_value | bucket.bucket_id |
+-------------------+-------------------+--+
| 0 | 1 |
| 12345 | 2 |
| 67890 | 3 |
+-------------------+-------------------+--+
> select * from buckvalue;
+---------------+------------------+--+
| buckvalue.id | buckvalue.value |
+---------------+------------------+--+
| 11 | 10 |
| 22 | 20000 |
| 33 | 80000 |
+---------------+------------------+--+
> select bucket_id, min_value, lead(min_value) over(order by bucket_id) as max1 from bucket;
INFO : OK
+------------+------------+--------+--+
| bucket_id | min_value | max1 |
+------------+------------+--------+--+
| 1 | 0 | 12345 |
| 2 | 12345 | 67890 |
| 3 | 67890 | NULL |
+------------+------------+--------+--+
> select t1.id, t1.value, t2.bucket_id from buckvalue t1 left outer join ( select bucket_id, min_value, lead(min_value) over(order by bucket_id) as max1 from bucket ) t2
where t1.value >= t2.min_value and t1.value < coalesce(t2.max1,99999);
+--------+-----------+---------------+--+
| t1.id | t1.value | t2.bucket_id |
+--------+-----------+---------------+--+
| 11 | 10 | 1 |
| 22 | 20000 | 2 |
| 33 | 80000 | 3 |
+--------+-----------+---------------+--+
I found a really simple query to do this. It works by finding all the bucket numbers for which the value is greater than the bucket's minimum value, and taking the maximum bucket_id.
create temporary table bucket as select * from (select 0 min_value, 1 bucket_id union select 12345, 2 union select 67890, 3) a;
create temporary table value as select * from (select 11 id, 10 value union select 22, 20000 union select 33, 80000) a;
select value.id, max(bucket.bucket_id) bucket_id
from value
join bucket
where value.value > bucket.min_value
group by value.id;

Make single record to multiple records in sql server

I have a records look like below
From two rows, I want to split ShiftPattern values and create multiple records and StartWeek will be created sequentially.
Final Query:
Split ShiftPattern Column and Create multiple records
Increase StartWeek like as 20, 21 to rotation.
Output result
This is what you need. Tested in fiddle.
SQLFiddle Demo
select q.locationid,q.employeeid,
case
when (lag(employeeid,1,null) over (partition by employeeid order by weekshiftpatternid)) is null
then startweek
else startweek + 1
end as rotation ,
q.weekshiftpatternid,
q.shiftyear
from
(
select locationid,employeeid, left(d, charindex(',', d + ',')-1) as weekshiftpatternid ,
startweek,shiftyear
from (
select *, substring(shiftpattern, number, 200) as d from MyTable locationid left join
(select distinct number from master.dbo.spt_values where number between 1 and 200) col2
on substring(',' + shiftpattern, number, 1) = ','
) t
) q
Output
+------------+------------+----------+--------------------+-----------+
| locationid | employeeid | rotation | weekshiftpatternid | shiftyear |
+------------+------------+----------+--------------------+-----------+
| 1 | 10000064 | 20 | 1006 | 2016 |
| 1 | 10000064 | 21 | 1008 | 2016 |
| 1 | 10000065 | 20 | 1006 | 2016 |
| 1 | 10000065 | 21 | 1008 | 2016 |
+------------+------------+----------+--------------------+-----------+
Similar:
In my test table my ID is your EmployeeID or however you want to work it.
SELECT
*,
LEFT(shiftBits, CHARINDEX(',', shiftBits + ',')-1) newShiftPattern,
StartWeek+ROW_NUMBER() OVER(PARTITION BY ID ORDER BY shiftBits ) as newStartWeek
FROM
(
SELECT
SUBSTRING(shiftPattern, number, LEN(shiftPattern)) AS shiftBits,
test2.*
FROM
test2,master.dbo.spt_values
WHERE
TYPE='P' AND number<LEN(shiftPattern)
AND SUBSTRING(',' + shiftPattern, number, 1) = ','
) AS x

SQL Server - Insert lines with null values when month doesn't exist

I have a table like this one:
Yr | Mnth | W_ID | X_ID | Y_ID | Z_ID | Purchases | Sales | Returns |
2015 | 10 | 1 | 5210 | 1402 | 2 | 1000.00 | etc | etc |
2015 | 12 | 1 | 5210 | 1402 | 2 | 12000.00 | etc | etc |
2016 | 1 | 1 | 5210 | 1402 | 2 | 1000.00 | etc | etc |
2016 | 3 | 1 | 5210 | 1402 | 2 | etc | etc | etc |
2014 | 3 | 9 | 880 | 2 | 7 | etc | etc | etc |
2014 | 12 | 9 | 880 | 2 | 7 | etc | etc | etc |
2015 | 5 | 9 | 880 | 2 | 7 | etc | etc | etc |
2015 | 7 | 9 | 880 | 2 | 7 | etc | etc | etc |
For each combination of (W, X, Y, Z) I would like to insert the months that don't appear in the table and are between the first and last month.
In this example, for combination (W=1, X=5210, Y=1402, Z=2), I would like to have additional rows for 2015/11 and 2016/02, where Purchases, Sales and Returns are NULL. For combination (W=9, X=880, Y=2, Z=7) I would like to have additional rows for months between 2014/4 and 2014/11, 2015/01 and 2015/04, 2016/06.
I hope I have explained myself correctly.
Thank you in advance for any help you can provide.
The process is rather cumbersome in this case, but quite possible. One method uses a recursive CTE. Another uses a numbers table. I'm going to use the latter.
The idea is:
Find the minimum and maximum values for the year/month combination for each set of ids. For this, the values will be turned into months since time 0 using the formula year*12 + month.
Generate a bunch of numbers.
Generate all rows between the two values for each combination of ids.
For each generated row, use arithmetic to re-extract the year and month.
Use left join to bring in the original data.
The query looks like:
with n as (
select row_number() over (order by (select null)) - 1 as n -- start at 0
from master.spt_values
),
minmax as (
select w_id, x_id, y_id, z_id, min(yr*12 + mnth) as minyyyymm,
max(yr*12 + mnth) as maxyyyymm
from t
group by w_id, x_id, y_id, z_id
),
wxyz as (
select minmax.*, minmax.minyyyymm + n.n,
(minmax.minyyyymm + n.n) / 12 as yyyy,
((minmax.minyyyymm + n.n) % 12) + 1 as mm
from minmax join
n
on minmax.minyyyymm + n.n <= minmax.maxyyyymm
)
select wxyz.yyyy, wxyz.mm, wxyz.w_id, wxyz.x_id, wxyz.y_id, wxyz.z_id,
<columns from t here>
from wxyz left join
t
on wxyz.w_id = t.w_id and wxyz.x_id = t.x_id and wxyz.y_id = t.y_id and
wxyz.z_id = t.z_id and wxyz.yyyy = t.yr and wxyz.mm = t.mnth;
Thank you for your help.
Your solution works, but I noticed it is not very good in terms of performance, but meanwhile I have managed to get a solution for my problem.
DECLARE #start_date DATE, #end_date DATE;
SET #start_date = (SELECT MIN(EOMONTH(DATEFROMPARTS(Yr , Mnth, 1))) FROM Table_Input);
SET #end_date = (SELECT MAX(EOMONTH(DATEFROMPARTS(Yr , Mnth, 1))) FROM Table_Input);
DECLARE #tdates TABLE (Period DATE, Yr INT, Mnth INT);
WHILE #start_date <= #end_date
BEGIN
INSERT INTO #tdates(PEriod, Yr, Mnth) VALUES(#start_date, YEAR(#start_date), MONTH(#start_date));
SET #start_date = EOMONTH(DATEADD(mm,1,DATEFROMPARTS(YEAR(#start_date), MONTH(#start_date), 1)));
END
DECLARE #pks TABLE (W_ID NVARCHAR(50), X_ID NVARCHAR(50)
, Y_ID NVARCHAR(50), Z_ID NVARCHAR(50)
, PerMin DATE, PerMax DATE);
INSERT INTO #pks (W_ID, X_ID, Y_ID, Z_ID, PerMin, PerMax)
SELECT W_ID, X_ID, Y_ID, Z_ID
, MIN(EOMONTH(DATEFROMPARTS(Ano, Mes, 1))) AS PerMin
, MAX(EOMONTH(DATEFROMPARTS(Ano, Mes, 1))) AS PerMax
FROM Table1
GROUP BY W_ID, X_ID, Y_ID, Z_ID;
INSERT INTO Table_Output(W_ID, X_ID, Y_ID, Z_ID
, ComprasLiquidas, RTV, DevManuais, ComprasBrutas, Vendas, Stock, ReceitasComerciais)
SELECT TP.DB, TP.Ano, TP.Mes, TP.Supplier_Code, TP.Depart_Code, TP.BizUnit_Code
, TA.ComprasLiquidas, TA.RTV, TA.DevManuais, TA.ComprasBrutas, TA.Vendas, TA.Stock, TA.ReceitasComerciais
FROM
(
SELECT W_ID, X_ID, Y_ID, Z_ID
FROM #tdatas CROSS JOIN #pks
WHERE Period BETWEEN PerMin And PerMax
) AS TP
LEFT JOIN Table_Input AS TA
ON TP.W_ID = TA.W_ID AND TP.X_ID = TA.X_ID AND TP.Y_ID = TA.Y_ID
AND TP.Z_ID = TA.Z_ID
AND TP.Yr = TA.Yr
AND TP.Mnth = TA.Mnth
ORDER BY TP.W_ID, TP.X_ID, TP.Y_ID, TP.Z_ID, TP.Yr, TP.Mnth;
I do the following:
Get the Min and Max date of the entire table - #start_date and #end_date variables;
Create an auxiliary table with all dates between Min and Max - #tdates table;
Get all the combinations of (W_ID, X_ID, Y_ID, Z_ID) along with the min and max dates of that combination - #pks table;
Create the cartesian product between #tdates and #pks, and in the WHERE clause I filter the results between the Min and Max of the combination;
Compute a LEFT JOIN of the cartesian product table with the input data table.

subtract data from single column

I have a database table with 2 columns naming piece and diff and type.
Here's what the table looks like
id | piece | diff | type
1 | 20 | NULL | cake
2 | 15 | NULL | cake
3 | 10 | NULL | cake
I want like 20 - 15 = 5 then 15 -10 = 5 , then so on so fort with type as where.
Result will be like this
id | piece | diff | type
1 | 20 | 0 | cake
2 | 15 | 5 | cake
3 | 10 | 5 | cake
Here's the code I have so far but i dont think I'm on the right track
SELECT
tableblabla.id,
(tableblabla.cast(pieces as decimal(7, 2)) - t.cast(pieces as decimal(7, 2))) as diff
FROM
tableblabla
INNER JOIN
tableblablaas t ON tableblabla.id = t.id + 1
Thanks for the help
Use LAG/LEAD window function.
Considering that you want to find Difference per type else remove Partition by from window functions
select id, piece,
Isnull(lag(piece)over(partition by type order by id) - piece,0) as Diff,
type
From yourtable
If you are using Sql Server prior to 2012 use this.
;WITH cte
AS (SELECT Row_number()OVER(partition by type ORDER BY id) RN,*
FROM Yourtable)
SELECT a.id,
a.piece,
Isnull(b.piece - a.piece, 0) AS diff,
a.type
FROM cte a
LEFT JOIN cte b
ON a.rn = b.rn + 1

Alternate of lead lag function in SQL Server 2008

I want to compare the current row with a value in the next row. SQL has LEAD and LAG functions to get the next and previous values but I can not use them because I am using SQL Server 2008.
So how do I get this?
I have table with output
+----+-------+-----------+-------------------------+
| Id | ActId | StatusId | MinStartTime |
+----+-------+-----------+-------------------------+
| 1 | 42 | 1 | 2014-02-14 11:17:21.203 |
| 2 | 42 | 1 | 2014-02-14 11:50:19.367 |
| 3 | 42 | 1 | 2014-02-14 11:50:19.380 |
| 4 | 42 | 6 | 2014-02-17 05:25:57.280 |
| 5 | 42 | 6 | 2014-02-19 06:09:33.150 |
| 6 | 42 | 1 | 2014-02-19 06:11:24.393 |
| 7 | 42 | 6 | 2014-02-19 06:11:24.410 |
| 8 | 42 | 8 | 2014-02-19 06:44:47.070 |
+----+-------+-----------+-------------------------+
What I want to do is if the current row status is 1 and the next row status is 6 and both times are the same (up to minutes) then I want to get the row where the status is 1.
Eg: Id 6 row has status 1 and Id 7 row has status 6 but both times are the same ie. 2014-02-19 06:11
So I want to get this row or id for status 1 ie. id 6
In your case, the ids appear to be numeric, you can just do a self-join:
select t.*
from table t join
table tnext
on t.id = tnext.id - 1 and
t.StatusId = 1 and
tnext.StatusId = 6 and
datediff(second, t.MinStartTime, tnext.MinStartTime) < 60;
This isn't quite the same minute. It is within 60 seconds. Do you actually need the same calendar time minute? If so, you can do:
select t.*
from table t join
table tnext
on t.id = tnext.id - 1 and
t.StatusId = 1 and
tnext.StatusId = 6 and
datediff(second, t.MinStartTime, tnext.MinStartTime) < 60 and
datepart(minute, t.MinStartTime) = datepart(minute, tnext.MinStartTime);
Just posting a more complex join using two different tables created with Gordon's foundation. Excuse the specific object names, but you'll get the gist. Gets the percentage change in samples from one to the next.
SELECT
fm0.SAMPLE curFMSample
, fm1.SAMPLE nextFMSample
, fm0.TEMPERATURE curFMTemp
, fm1.TEMPERATURE nextFMTemp
, ABS(CAST((fm0.Temperature - fm1.Temperature) AS DECIMAL(4, 0)) / CAST(fm0.TEMPERATURE AS DECIMAL(4, 0))) AS fmTempChange
, fm0.GAUGE curFMGauge
, fm1.GAUGE nextFMGauge
, ABS(CAST((fm0.GAUGE - fm1.GAUGE) AS DECIMAL(4, 4)) / CAST(fm0.GAUGE AS DECIMAL(4, 4))) AS fmGaugeChange
, fm0.WIDTH curFMWidth
, fm1.WIDTH nextFMWidth
, ABS(CAST((fm0.Width - fm1.Width) AS DECIMAL(4, 2)) / CAST(fm0.Width AS DECIMAL(4, 2))) AS fmWidthChange
, cl0.TEMPERATURE curClrTemp
, cl1.TEMPERATURE nextClrTemp
, ABS(CAST((cl0.Temperature - cl1.Temperature) AS DECIMAL(4, 0)) / CAST(cl0.TEMPERATURE AS DECIMAL(4, 0))) AS clrTempChange
FROM
dbo.COIL_FINISHING_MILL_EXIT_STR02 fm0
INNER JOIN dbo.COIL_FINISHING_MILL_EXIT_STR02 fm1 ON (fm0.SAMPLE = fm1.SAMPLE - 1 AND fm1.coil = fm0.coil)
INNER JOIN dbo.COIL_COILER_STR02 cl0 ON fm0.coil = cl0.coil AND fm0.SAMPLE = cl0.SAMPLE
INNER JOIN dbo.COIL_COILER_STR02 cl1 ON (cl0.SAMPLE = cl1.SAMPLE - 1 AND cl1.coil = cl0.coil)
WHERE
fm0.coil = 2015515872
Well, I would suggest a very simple solution if you do not have a sequential row id but a different step (if some records were deleted for example..):
declare #t table(id int, obj_name varchar(5))
insert #t select 1,'a'
insert #t select 5,'b'
insert #t select 22,'c'
insert #t select 543,'d'
---------------------------------
select *from #t
Example Source Table #t:
---------------------------------
id obj_name
1 a
5 b
22 c
543 d
---------------------------------
Select with self join
select obj_name_prev=tt.obj_name, obj_name_next=min(t.obj_name)
from #t t
join #t tt on tt.id < t.id
group by tt.obj_name
Result:
---------------------------------
obj_name_prev obj_name_next
a b
b c
c d
---------------------------------