I want to flatten parent-child tables for data analysis purposes.
I have Service order table tssoc210 as
orno|acln
1 |10
1 |20
2 |20
.
.
it's activities(labour,material,other) are maintained in 3 other tables as
tssoc220 (for labour)
orno|acln|lino|invn|eqan|asto
1 |10 |A |600 |2 |120
1 |10 |B |607 |1 |100
.
.
tssoc230 (for materials)
orno|acln|lino|invn|eqan|asto
1 |10 |L1 |700 |1 |110
1 |10 |L2 |704 |3 |200
1 |10 |L3 |407 |4 |100
1 |20 |L1 |708 |1 |100
2 |20 |L1 |790 |1 |200
.
.
tssoc240(for other)
orno|acln|lino|invn|eqan|asto
1 |10 |M1 |400 |2 |500
2 |20 |M1 |490 |1 |100
.
.
I want to join these tables as
orno|acln|l_lino|l_invn|l_eqan|l_asto|m_lino|m_invn|m_eqan|m_asto|o_lino|o_invn|o_eqan|o_asto
1 |10 |A |600 |2 |120 |NULL |NULL |NULL |NULL |NULL |NULL |NULL |NULL
1 |10 |B |607 |1 |100 |NULL |NULL |NULL |NULL |NULL |NULL |NULL |NULL
1 |10 | NULL |NULL |NULL |NULL |L1 |700 |1 |110 |NULL |NULL |NULL |NULL
1 |10 | NULL |NULL |NULL |NULL |L2 |704 |3 |200 |NULL |NULL |NULL |NULL
1 |10 | NULL |NULL |NULL |NULL |L3 |407 |4 |100 |NULL |NULL |NULL |NULL
1 |10 | NULL |NULL |NULL |NULL |NULL |NULL |NULL |NULL |M1 |400 |2 |500
1 |20 | NULL |NULL |NULL |NULL |L1 |708 |1 |100 |NULL |NULL |NULL |NULL
2 |20 | NULL |NULL |NULL |NULL |L1 |790 |1 |200 |NULL |NULL |NULL |NULL
2 |20 | NULL |NULL |NULL |NULL |NULL |NULL |NULL |NULL |M1 |490 |1 |100
.
.
If I left join tssoc220,tssoc230, tssoc240 with tssoc210(tssoc210 as a left table), it duplicates the row.
left join tssoc220 ON tssoc210.orno = tssoc220.orno and tssoc210.acln = tssoc220.acln
left join tssoc230 ON tssoc210.orno = tssoc230.orno and tssoc210.acln = tssoc230.acln
left join tssoc240 ON tssoc210.orno = tssoc240.orno and tssoc210.acln = tssoc240.acln
Where am I going wrong?
You will need to write 3 queries that join only 1 table and union them.
SELECT tssoc210.orno,tssoc210.acln,tssoc220.l_lino,tssoc220.l_invn,tssoc220.l_eqan,tssoc220.l_asto,NULL as m_lino,NULL as m_invn,NULL as m_eqan,NULL as m_asto,NULL as o_lino,NULL as o_invn,NULL as o_eqan,NULL as o_asto
FROM tssoc210
left join tssoc220 ON tssoc210.orno = tssoc220.orno and tssoc210.acln = tssoc220.acln
UNION ALL
SELECT tssoc210.orno,tssoc210.acln,NULL as l_lino,NULL as l_invn,NULL as l_eqan,NULL as l_asto,tssoc230.m_lino,tssoc230.m_invn,tssoc230.m_eqan,tssoc230.m_asto,NULL as o_lino,NULL as o_invn,NULL as o_eqan,NULL as o_asto
FROM tssoc210
left join tssoc230 ON tssoc210.orno = tssoc230.orno and tssoc210.acln = tssoc230.acln
UNION ALL
SELECT tssoc210.orno,tssoc210.acln,NULL as l_lino,NULL as l_invn,NULL as l_eqan,NULL as l_asto,,NULL as m_lino,NULL as m_invn,NULL as m_eqan,NULL as m_asto,tssoc240.o_lino,tssoc240.o_invn,tssoc240.o_eqan,tssoc240.o_asto
FROM tssoc210
left join tssoc240 ON tssoc210.orno = tssoc240.orno and tssoc210.acln = tssoc240.acln
Related
I have a table with StudentIds ordered by row number, I want to update NewDummyNumber column with the values that are calculated by some logic.
This is my original table:
|StudentId|RegNumber|RowNum|NewDummyNo|
+---------+---------+------+----------+
|282840 |15005 |1 |NULL |
|282841 |15006 |2 |NULL |
|282877 |15040 |3 |NULL |
|282878 |15041 |4 |NULL |
|282879 |15042 |5 |NULL |
|282880 |15043 |6 |NULL |
|282881 |15044 |7 |NULL |
|282882 |15045 |8 |NULL |
|282837 |15002 |9 |NULL |
|282838 |15003 |10 |NULL |
---------------------------------------
The logic for NewDummyColumn is:
if SkipNumber = 2 then the records will be shuffle like 1st record as it is with dummy number as 1001 then two records are skip for now and 4th record newdummy number will be 1002 and so on up to 10 then this cycle will continue. The result should be like
-- for first Cycle
|StudentId|RegNumber|RowNum|NewDummyNo|
+---------+---------+------+----------+
|282840 |15005 |1 |1001 |
|282841 |15006 |2 |NULL |
|282877 |15040 |3 |NULL |
|282878 |15041 |4 |1002 |
|282879 |15042 |5 |NULL |
|282880 |15043 |6 |NULL |
|282881 |15044 |7 |1003 |
|282882 |15045 |8 |NULL |
|282837 |15002 |9 |NULL |
|282838 |15003 |10 |1004 |
---------------------------------------
For the second cycle:
|StudentId|RegNumber|RowNum|NewDummyNo|
+---------+---------+------+----------+
|282840 |15005 |1 |1001 |
|282841 |15006 |2 |NULL |
|282877 |15040 |3 |1005 |
|282878 |15041 |4 |1002 |
|282879 |15042 |5 |NULL |
|282880 |15043 |6 |1006 |
|282881 |15044 |7 |1003 |
|282882 |15045 |8 |NULL |
|282837 |15002 |9 |1007 |
|282838 |15003 |10 |1004 |
---------------------------------------
For the third cycle
|StudentId|RegNumber|RowNum|NewDummyNo|
---------------------------------------
|282840 |15005 |1 |1001 |
|282841 |15006 |2 |1008 |
|282877 |15040 |3 |1005 |
|282878 |15041 |4 |1002 |
|282879 |15042 |5 |1009 |
|282880 |15043 |6 |1006 |
|282881 |15044 |7 |1003 |
|282882 |15045 |8 |1010 |
|282837 |15002 |9 |1007 |
|282838 |15003 |10 |1004 |
---------------------------------------
Now NewDummyNo colunm not contain any NULL Values so this is the final result.
Please suggest how to achieve this - my #table is:
create table #DUMMYNUMBER
(
StudentId int,
OrderStudentRegNumber int,
RwNumber int,
NewDummyNumber int
)
insert into #DUMMYNUMBER(StudentId, OrderStudentRegNumber, RwNumber)
values
(282840, 15005, 1),
(282841, 15006, 2),
(282877, 15040, 3),
(282878, 15041, 4),
(282879, 15042, 5),
(282880, 15043, 6),
(282881, 15044, 7),
(282882, 15045, 8),
(282837, 15002, 9),
(282838, 15003, 10)
If number of records and skipNumber+1 are coprimes, you can do following:
DECLARE #skip int = 2;
DECLARE #total int = (SELECT COUNT(*) FROM #DUMMYNUMBER);
DECLARE #skip int = #skipNumber+1;
SELECT TOP(#total) StudentId, OrderStudentRegNumber, RwNumber, 1000+ROW_NUMBER() OVER (ORDER BY N) NewDummyNo FROM (
SELECT *, R+A*#total N, CASE WHEN (R+A*#total)%#skip=1 THEN 'X' END X FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY RwNumber) R
FROM #DUMMYNUMBER
) Num
CROSS APPLY (VALUES (0),(1),(2)) T(A) --number of loops, equal to (skip+1), use tally or recursive generator if needed
) T WHERE X IS NOT NULL
If they are not, infinite loop happens.
How to move the data from different rows with same ID in same rows but different column?
For example,
I have this table
tblEx
--------------
|ID|Buy |Sell|
|--+----+----|
|1 |10 | |
|1 | |11 |
|2 |20 | |
|2 | |0 |
|3 |0 | |
|3 | |30 |
--------------
Desired Output:
--------------
|ID|Buy |Sell|
|--+----+----|
|1 |10 |11 |
|2 |20 |0 |
|3 |0 |30 |
--------------
Based from the given example and desired result, you can use MAX()
SELECT ID, MAX(Buy) AS Buy, MAX(Sell) AS Sell
FROM TableName
GROUP BY ID
I have a data table that kind of looks like this.
|Key|LotId|TransactionType|Quantity|Destination
|1 |A |Transform |NULL |Foo
|2 |A |Transform |NULL |Bar
|3 |A |Consume |100 |NULL
|4 |B |Transform |NULL |Bob
|5 |B |Transform |NULL |Fred
|6 |B |Consume |75 |NULL
|7 |B |Consume |50 |NULL
|8 |B |Transform |NULL |Sally
|9 |B |Transform |NULL |Fred
|10 |B |Consume |60 |NULL
|11 |C |Transform |NULL |Bar
|12 |C |Transform |NULL |Fred
|13 |C |Consume |25 |NULL
The transform lines tell me where my quantity went and the consume line tells me how much quantity was use. The consume line applies to all previous transform lines for that LotId up to either the previous LotId or if it is the same LotId the previous transform & consume grouping. And to throw one added wrench the number of transform and consume lines within a group are variable. The one thing I do have working for me is that transform lines come first, then consume, the next time I encounter transforms I know a new grouping has started.
|Key|LotId|TransactionType|Quantity|Destination|Grouping
|1 |A |Transform |NULL |Foo |A1
|2 |A |Transform |NULL |Bar |A1
|3 |A |Consume |100 |NULL |A1
---------------------------------------------------------
|4 |B |Transform |NULL |Bob |B1
|5 |B |Transform |NULL |Fred |B1
|6 |B |Consume |75 |NULL |B1
|7 |B |Consume |50 |NULL |B1
---------------------------------------------------------
|8 |B |Transform |NULL |Sally |B2
|9 |B |Transform |NULL |Fred |B2
|10 |B |Consume |60 |NULL |B2
---------------------------------------------------------
|11 |C |Transform |NULL |Bar |C1
|12 |C |Transform |NULL |Fred |C1
|13 |C |Consume |25 |NULL |C1
(for the purposes of this example we'll just assume that the quantity is split evenly across all parties)
Group A1 there was 100 split between Foo & Bar
Group B1 there was 125 split between Bob and Fred
Group B2 there was 60 split between Sally & Fred
Group C1 there was 25 split between Bar and Fred
Using the sql RANK(), DENSE_RANK(), & ROW_NUMBER() windowing I am trying to work out a query which will give me this grouping. Once I'm able to get this grouping I should then be able to join the data back onto itself and ultimately determine how much each one of my destinations received.
This is on SQL2008.
Using a combination of a common table expression, outer apply(), and dense_rank()
note: I changed the column Key to tKey so I would not have to use square brackets around it.
;with cte as (
select *
, PrevTransactionType=isnull(x.Prev_TransactionType,'Consume')
from t
outer apply (
select top 1
Prev_TransactionType = TransactionType
from t as i
where i.tKey < t.tKey
order by i.tKey desc
) as x
)
select t.tKey, t.LotId, t.TransactionType, t.Quantity, t.Destination
, Grouping = LotId + convert(varchar(10),dense_rank() over (
partition by LotId
order by GroupNumber
)
)
from cte as t
outer apply (
select top 1
GroupNumber = i.tKey
from cte as i
where i.tKey <= t.tKey
and i.TransactionType = 'Transform'
and i.PrevTransactionType = 'Consume'
order by i.tKey desc
) x
test setup: http://rextester.com/LWV40248
results:
+------+-------+-----------------+----------+-------------+----------+
| tKey | LotId | TransactionType | Quantity | Destination | Grouping |
+------+-------+-----------------+----------+-------------+----------+
| 1 | A | Transform | NULL | Foo | A1 |
| 2 | A | Transform | NULL | Bar | A1 |
| 3 | A | Consume | 100 | NULL | A1 |
| 4 | B | Transform | NULL | Bob | B1 |
| 5 | B | Transform | NULL | Fred | B1 |
| 6 | B | Consume | 75 | NULL | B1 |
| 7 | B | Consume | 50 | NULL | B1 |
| 8 | B | Transform | NULL | Sally | B2 |
| 9 | B | Transform | NULL | Fred | B2 |
| 10 | B | Consume | 60 | NULL | B2 |
| 11 | C | Transform | NULL | Bar | C1 |
| 12 | C | Transform | NULL | Fred | C1 |
| 13 | C | Consume | 25 | NULL | C1 |
+------+-------+-----------------+----------+-------------+----------+
I have small question about SQL Server.
I have a table with sample data like this:
id | month | stat | count
---------------------------------
1 | 1 | admit | 7
2 | 8 | admit | 47
1 | 7 | admit | 28
2 | 9 | admit | 11
3 | 12 | dischr | 4
4 | 10 | openc | 5
1 | 11 | admit | 1
2 | 6 | admit | 5
2 | 4 | admit | 8
1 | 3 | dischr | 10
2 | 2 | admit | 30
3 | 5 | dischr | 20
1 | 8 | admit | 13
3 | 8 | dischr | 1
4 | 9 | admit | 30
2 | 10 | admit | 20
3 | 10 | deschr | 20
Based on this when month=1 then January and when month=2 then February all the way through 12, based on that condition I got output like below.
Month |id |Admit |Dischr |OpenC
August |1 |13 |NULL |NULL
January |1 |7 |NULL |NULL
July |1 |28 |NULL |NULL
March |1 |NULL |10 |NULL
November|1 |1 |NULL |NULL
April |2 |8 |NULL |NULL
August |2 |47 |NULL |NULL
February|2 |30 |NULL |NULL
June |2 |5 |NULL |NULL
October 2 |20 |NULL |NULL
September|2 |11 |NULL |NULL
August |3 |NULL |1 |NULL
December|3 |NULL |4 |NULL
May |3 |NULL |20 |NULL
October |3 |NULL |NULL |NULL
October |4 |NULL |NULL |5
September|4 |30 |NULL |NULL
but I want output like month wise proper order and output look like below
Month |id |Admit |Dischr |OpenC
January |1 |7 |NULL |NULL
February|2 |30 |NULL |NULL
March |1 |NULL |10 |NULL
April |2 |8 |NULL |NULL
May |3 |NULL |20 |NULL
June |2 |5 |NULL |NULL
July |1 |28 |NULL |NULL
August |1 |13 |NULL |NULL
August |2 |47 |NULL |NULL
August |3 |NULL |1 |NULL
September|2 |11 |NULL |NULL
September|4 |30 |NULL |NULL
October |2 |20 |NULL |NULL
October |3 |NULL |NULL |NULL
October |4 |NULL |NULL |5
November|1 |1 |NULL |NULL
December|3 |NULL |4 |NULL
Please tell me query how to solve this issue in SQL Server.
You need to convert the month column to date and use it in order by with ID
SELECT [Month],
id,
Admit,
Dischr,
OpenC
FROM yourTable
ORDER BY Cast([Month] + '01 2010' AS DATE),Id
or
order by DATEPART(MM,[Month]+ ' 01 2010'),Id
Note : '1 2010' in cast is just a static value to convert the month varchar column to date
Add order by clause to your query to ensure your data is ordered according to your requirement. Something like this
SELECT ....
FROM yourTable
ORDER BY Month, Id
I just wanted to ask something, I want to update a table, but this table 300k rows, it is taking about 1.8 - 2.3 seconds per row this is the table I need to update, if name match with a column i need to set the value of column All,
ID |cexp_cod |All |name |New |Normal |Vip
1 |13 |9 |Vip |NULL |NULL |NULL
2 |16 |9 |Vip |NULL |NULL |NULL
3 |16 |6 |Normal |NULL |NULL |NULL
4 |18 |9 |Vip |NULL |NULL |NULL
5 |23 |9 |New |NULL |NULL |NULL
6 |25 |9 |New |NULL |NULL |NULL
7 |26 |9 |Vip |NULL |NULL |NULL
8 |27 |9 |New |NULL |NULL |NULL
9 |40 |9 |Vip |NULL |NULL |NULL
10 |43 |9 |Vip |NULL |NULL |NULL
11 |43 |6 |Normal |NULL |NULL |NULL
and this is my query:
DECLARE #loop smallint = 0
,#v_xp_cod varchar(max) = 0
,#v_name varchar(MAX) = NULL
,#v_pond varchar(max) = 0
,#v_id bigint = 0
WHILE #loop = 0
BEGIN
SELECT TOP 1 #v_xp_cod = query01.xp_cod
,#v_name = query01.name
,#v_pond = query01.All
,#v_id = query01.ID
FROM (
SELECT xp_cod
, name
, All
, ID
FROM temp WITH(NOLOCK)
) AS query01
WHERE query01.ID > #v_id
ORDER BY query01.ID ASC
IF ##rowcount=0
BEGIN
SET #loop=1
END
ELSE -- update
BEGIN
DECLARE #i_update nvarchar(MAX)=null
SELECT #i_update = 'UPDATE temp
SET [' +#v_name+ '] = '+#v_pond+'
WHERE xp_cod = ' + #v_xp_cod
EXECUTE sp_executesql #i_update
END
END
Perhaps try rewriting the query using a different approach or format:
UPDATE MyTable
SET MyColumnName =
( SELECT table2.Name
FROM table2
WHERE table2.my_id = MyTable.id)
WHERE EXISTS
( SELECT table2.Name
FROM table2
WHERE table2.my_id = MyTable.id);