Union and Order By (SQL Server) - sql-server

Consider a table A and table B like :
Table A:
debit credit row
-----------------------
10 0 1
0 10 1
20 0 2
0 20 2
30 0 3
0 30 3
Table B:
debit credit row
-----------------------
10 0 1
0 10 1
20 0 2
0 20 2
30 0 3
0 30 3
Result:
debit credit row
--------------------
10 0 1
20 0 2
30 0 3
0 10 1
0 20 2
0 30 3
I'm trying to union all table A, B and show debit first, then sort it by row column.

by definition, the individual SELECTs making up a UNION are not allowed to contain an ORDER BY clause. The only ORDER BY clause allowed is at the end of the UNION and it applies to the entire UNION, making xxx UNION yyy ORDER BY zzz the eqivalent of (xxx UNION yyy) ORDER BY zzz
Meaning:
Invalid:
Select debit,credit,row
from
(
Select debit,credit,row
From table a
Where 'condition'
Union
Select debit,credit,row
From table b
Where 'condition 2'
) results
order by debit, row
Valid:
Select debit,credit,row
From table a
Where 'condition'
Union
Select debit,credit,row
From table b
Where 'condition 2'
Order by debit, row

Related

How to check values of different rows of a table

I have below sample input table. In real it has lots of records.
Input:
ID
Classification
123
1
123
2
123
3
123
4
657
1
657
3
657
4
For a 'ID', I want it's records should have 'Classification' column contains all the values 1, 2, 3 and 4. If any of these values are not present then that ID's records should be considered as an exception. The output should be as below.
ID
Classification
Flag
123
1
0
123
2
0
123
3
0
123
4
0
657
1
1
657
3
1
657
4
1
Can someone please help me with how can this can be achieved in sql server.
Thanks.
There are a couple of options here, which is more performant is up to you to test, not me (especially when I don't know what indexes you have). One uses conditional aggregation, to check that all the values are there, and the other uses a subquery and counts the DISTINCT values (as I don't know if there could be duplicate classifications):
SELECT *
INTO dbo.YourTable
FROM (VALUES(123,1),
(123,2),
(123,3),
(123,4),
(657,1),
(657,3),
(657,4))V(ID,Classification);
GO
CREATE CLUSTERED INDEX CI_YourIndex ON dbo.YourTable (ID,Classification);
GO
SELECT ID,
Classification,
CASE WHEN COUNT(CASE YT.Classification WHEN 1 THEN 1 END) OVER (PARTITION BY ID) > 0
AND COUNT(CASE YT.Classification WHEN 2 THEN 1 END) OVER (PARTITION BY ID) > 0
AND COUNT(CASE YT.Classification WHEN 3 THEN 1 END) OVER (PARTITION BY ID) > 0
AND COUNT(CASE YT.Classification WHEN 4 THEN 1 END) OVER (PARTITION BY ID) > 0 THEN 1 ELSE 0
END AS Flag
FROM dbo.YourTable YT;
GO
SELECT ID,
Classification,
CASE (SELECT COUNT(DISTINCT sq.Classification)
FROM dbo.YourTable sq
WHERE sq.ID = YT.ID
AND sq.Classification IN (1,2,3,4)) WHEN 4 THEN 1 ELSE 0
END AS Flag
FROM dbo.YourTable YT;
GO
DROP TABLE dbo.YourTable;

Repeat a sum as a column in SQL

I have a table
WO# Seg# Part# QTY TotSale FlatSale
1 1 1 5 35 159
1 1 2 2 100 159
1 2 3 3 50 50
I need to calculate the FlatSale/SUM(TotSale) for each Seq# & WO# but do not group Seg# into one row.
I need this
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 1.177
1 1 2 2 100 159 1.177
1 2 3 3 50 50 1
With my code I am able to only do the division on each individual line like this:
select *, FlatSale/TotSale as Calc from table
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 4.54
1 1 2 2 100 159 1.59
1 2 3 3 50 50 1
I wouldn't mind leaving my Calc column and adding another column if that's the easiest way to do it.
Maybe something like this:
SELECT
[WO#],[Seg#],[Part#],[QTY],[TotSale],[FlatSale]
((FlatSale*100)/(SUM([TotSale]) OVER(PARTITION BY [Seg#] ORDER BY [Seg#])))/100 AS Calc
FROM SomeTable
You can use a lateral join. Here's something quick (not tested as I don't have access to mssql at the moment):
select *, x.CalcPrice as Calc
from table t
outer apply (
select t.FlatSale/SUM(ix.TotSale) CalcPrice
from table ix where ix.[WO#] = t.[WO#]
and ix.[Seg#] = t.[Seg#]) x
Something like that.

SQL Server 2008 - merge rows when condition matched

I am running a stored procedure and getting the following value.
Name ID NewID Qty Rqty Total
Test1 1 5 4 9
Test2 10 1001 3 0 3
Test2 1001 4 2 6
Test3 15 1005 0 0 0
Test3 1005 3 4 7
If you look the Test3, where first id 15 has a new id 1005 But the Qty and Rqty is 0, next line I am getting ID 1005 and Qty, Rqty 3 and 4, total 7and this is correct.
What I am trying to do is when any ID got a new ID and Qty, Rqty both are 0, I need the following output in on row
Test3 15 1005 3 4 7
So, my final results will be -
Name ID NewID Qty Rqty Total
Test1 1 5 4 9
Test2 10 1001 3 0 3
Test2 1001 4 2 6
Test3 15 1005 3 4 7
My stored procedure is -
select Name, ID, NewID, Qty, RQty, SUM(Qty + RQty) as Total
from table1
Group By Name, ID, NewID, Qty, RQty
Order by Name
Could anyone help to solve this issue please.
Thanks
You will need to generate a psuedo "grouping" ID and NewID based on your conditions, group on those fields and select the MIN and MAX of the original ID and NewID along with aggregates of your other values. e.g.
CREATE TABLE dbo.Tests
(
Name varchar(10),
ID int,
[NewID] int NULL,
Qty int,
Rqty int
);
INSERT dbo.Tests (Name,ID,[NewID],Qty,Rqty)
--VALUES ('Test1',1,NULL,5,4)
-- ,('Test2',10,1001,3,0)
-- ,('Test2',1001,NULL,4,2)
-- ,('Test3',15,1005,0,0)
-- ,('Test3',1005,NULL,3,4);
VALUES ('test1',1,101,0,0)
,('test1',101,NULL,2,4)
,('test2',2,102,0,0)
,('test2',102,NULL,4,5)
,('test3',3,103,0,0)
,('test3',103,NULL,3,3)
,('test4',4,104,0,0)
,('test4',104,NULL,1,3)
,('test5',5,105,0,0)
,('test5',105,NULL,3,6);
SELECT t.Name,
min(t.ID) AS ID,
max(t.[NewID]) AS [NewID],
sum(t.Qty) AS Qty,
sum(t.Rqty) AS Rqty,
sum(t.Qty)+sum(t.Rqty) AS Total
FROM dbo.Tests AS t
CROSS APPLY (VALUES(CASE WHEN Qty = 0 AND Rqty = 0 AND t.[NewID] IS NOT NULL THEN [NewID] ELSE ID END,
CASE WHEN Qty = 0 AND Rqty = 0 AND t.[NewID] IS NOT NULL THEN -1 ELSE coalesce([NewID],-1) END)
) x(GroupingID, GroupingNewID)
GROUP BY Name,x.GroupingID,x.GroupingNewID
ORDER BY Name,max(t.ID);

Get Min and Max Dates from SQL Server SQL

Data in my table looks like this
PAY_END_DT Sal
10/27/2013 0
11/10/2013 0
11/24/2013 2473.14
12/08/2013 0
01/19/2014 0
02/02/2014 0
02/16/2014 0
My desired result should be like as below
10/27/2013 11/10/2013
12/08/2013 02/16/2014
I need a SQL to generate this result set.. please help
SELECT
employee_id,
MIN(pay_end_dt) AS island_min_pay_end_dt,
MAX(pay_end_dt) AS island_max_pay_end_dt
FROM
(
SELECT
pay_end_dt,
ROW_NUMBER() OVER (PARTITION BY employee_id,
ORDER BY pay_end_dt ) AS full_set_ordinal,
ROW_NUMBER() OVER (PARTITION BY employee_id, sal
ORDER BY pay_end_dt ) AS zero_set_ordinal
FROM
yourTable
)
AS sorted_set
WHERE
sal = 0
GROUP BY
employee_id,
full_set_ordinal - zero_set_ordinal
;
Using your data as an example:
PAY_END_DT Sal FULL_SET_ORIDINAL ZERO_SET_ORDINAL "FULL - ZERO"
10/27/2013 0 1 1 0
11/10/2013 0 2 2 0
11/24/2013 2473.14 3 1 2
12/08/2013 0 4 3 1
01/19/2014 0 5 4 1
02/02/2014 0 6 5 1
02/16/2014 0 7 6 1
Which then allows us to include only the rows WHERE sal = 0 and then GROUP BY "FULL - ZERO" to get our two sets, and then finally apply the MIN() and MAX() functions.
As stated in a comment, this is known as "Gaps and Islands".
1 1 1 1
0 0 0 0 0
1 2 3 4 5 6 7 8 9 - ordinal from the whole set
1 2 3 4 - ordinal from just the "islands"
1 2 3 4 5 - ordinal from just the "gaps"
2 2 2 3 - ordinal of the "islands" (whole_set_id - islands_id)
0 0 3 4 4 - ordinal of the "gaps" (whole_set_id - gaps_id)
;)
SELECT "10/27/2013 11/10/2013"
UNION
SELECT "12/08/2013 02/16/2014"

A group by challenge

Let's say I have this table MyTbl
Record Id_try Id Type IsOk DateOk
1 1 MYDB00125 A 0 NULL
2 1 MYDB00125 B 1 2012-07-19 20:10:05.000
3 1 MYDB00125 A 0 2012-07-25 14:10:05.000
4 2 MYDB00125 A 0 2012-07-19 22:10:05.000
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 C 0 NULL
And I want a group by that brings me for each Id and Type my last "Id_Try Record".
SELECT Id, MAX(Id_Try), MyTbl.Type, IsOK, MAX(DateOk) from MyTbl
GROUP BY Id, MyTbl.Type, IsOK
Won't do, because It'll bring me the last Id_Try AND the last date (Date of record 3 in the example). And I don't care if its the last date or not, I need the date of the last Id_Try.
Is this only solved by a subselect? or a having clause could do?
This is the result expected:
Record Id_try Id Type IsOk DateOk
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 B 0 NULL
I think you will need to break this into two pieces:
with maxIDTry as
(
SELECT MAX(Id_try) as maxId, ID
FROM MyTable
GROUP BY ID
)
SELECT * FROM MyTable as mt
INNER JOIN maxIDTry as max
ON mt.id_try = max.maxId AND mt.id = max.id
I think you want this:
select * FROM
(
select *, row_number() over (partition by id,type order by Id_try desc) as position from mytbl
) foo
where position = 1
order by record
http://www.sqlfiddle.com/#!3/95742/5
Your sample result set lists
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 A 0 NULL
But that doesn't make sense since you're saying the ID and the Id_try have the same value. I assume you meant for Id_try to be 2 maybe? Otherwise I think my results match up.
Hope this helps.
SELECT A.Record, A.Id_try, A.Id, A.Type, A.IsOk, A.DateOk
FROM MyTbl A INNER JOIN (
SELECT MAX(Id_Try) Id_Try, Id, B1.Type
from MyTbl B1
GROUP BY Id, B1.Type) AS B
ON A.Id_Try = B.Id_Try AND A.Id = B.Id AND A.Type = B.Type
ORDER BY A.RECORD

Resources