How to get values alternate for ROW_NUMBER()? - sql

I have a table with values like these:
Name Order Innings
Suresh 1 1
Ramesh 2 1
Sekar 3 1
Raju 1 2
Vinoth 2 2
Ramu 3 2
I want the result be like this:
1stInn 2ndInn Order
Suresh Raju 1
Ramesh Vinoth 2
Sekar Ramu 3
I got the result using ROW_NUMBER() in SQL Server.
I want the same result in SQL Compact, But I can't use ROW_NUMBER() in SQL Compact.
I'm using SQL Compact version - 4.0.8482.1
How can I get the result?

Why do you need ROW_NUMBER()? you can use conditional aggregation using CASE EXPRESSION :
SELECT MAX(CASE WHEN t.innings = 1 THEN t.name END) as 1stInn,
MAX(CASE WHEN t.innings = 2 THEN t.name END) as 2sndInn,
t.Order
FROM YourTable t
GROUP BY t.order

simple Pivot will give the similar result
DECLARE #Table1 TABLE
( Name varchar(6), [Order] int, Innings int)
;
INSERT INTO #Table1
( Name , [Order] , Innings )
VALUES
('Suresh', 1, 1),
('Ramesh', 2, 1),
('Sekar', 3, 1),
('Raju', 1, 2),
('Vinoth', 2, 2),
('Ramu', 3, 2)
;
select [1] AS '1stinn',[2] AS '2ndinn',[order] from(
select Name , [Order] , Innings from #Table1)T
PIVOT (MAX(NAME) FOR Innings IN ([1],[2]))PVT

Related

Issue with Row_Number() Over Partition

I've been trying to reset the row_number when the value changes on Column Value and I have no idea on how should i do this.
This is my SQL snippet:
WITH Sch(SubjectID, VisitID, Scheduled,Actual,UserId,RLev,SubjectTransactionID,SubjectTransactionTypeID,TransactionDateUTC,MissedVisit,FieldId,Value) as
(
select
svs.*,
CASE WHEN stdp.FieldID = 'FrequencyRegime' and svs.SubjectTransactionTypeID in (2,3) THEN
stdp.FieldID
WHEN stdp.FieldID is NULL and svs.SubjectTransactionTypeID = 1
THEN NULL
WHEN stdp.FieldID is NULL
THEN 'FrequencyRegime'
ELSE stdp.FieldID
END AS [FieldID],
CASE WHEN stdp.Value is NULL and svs.SubjectTransactionTypeID = 1
THEN NULL
WHEN stdp.Value IS NULL THEN
(SELECT TOP 1 stdp.Value from SubjectTransaction st
JOIN SubjectTransactionDataPoint STDP on stdp.SubjectTransactionID = st.SubjectTransactionID and stdp.FieldID = 'FrequencyRegime'
where st.SubjectID = svs.SubjectID
order by st.ServerDateST desc)
ELSE stdp.Value END AS [Value]
from SubjectVisitSchedule svs
left join SubjectTransactionDataPoint stdp on svs.SubjectTransactionID = stdp.SubjectTransactionID and stdp.FieldID = 'FrequencyRegime'
)
select
Sch.*,
CASE WHEN sch.Value is not NULL THEN
ROW_NUMBER() over(partition by Sch.Value, Sch.SubjectID order by Sch.SubjectID, Sch.VisitID)
ELSE NULL
END as [FrequencyCounter],
CASE WHEN Sch.Value = 1 THEN 1--v.Quantity
WHEN Sch.Value = 2 and (ROW_NUMBER() over(partition by Sch.Value, Sch.SubjectID order by Sch.SubjectID, Sch.VisitID) % 2) <> 0
THEN 0
WHEN Sch.Value = 2 and (ROW_NUMBER() over(partition by Sch.Value, Sch.SubjectID order by Sch.SubjectID, Sch.VisitID) % 2) = 0
THEN 1
ELSE NULL
END AS [DispenseQuantity]
from Sch
--left join VisitDrugAssignment v on v.VisitID = Sch.VisitID
where SubjectID = '4E80718E-D0D8-4250-B5CF-02B7A259CAC4'
order by SubjectID, VisitID
This is my Dataset:
Based on the Dataset, I am trying to reset the FrequencyCounter to 1 every time the value changes for each subject, Right now it does 50% of what I want, It is counting when the value 1 or 2 is found, but when value 1 comes again after value 2 it continues the count from where it left. I want every time the value is changes the count to also start from the beginning.
It's difficult to reproduce and test without sample data, but if you want to know how to number rows based on change in column value, next approach may help. It's probably not the best one, but at least will give you a good start. Of course, I hope I understand your question correctly.
Data:
CREATE TABLE #Data (
[Id] int,
[Subject] varchar(3),
[Value] int
)
INSERT INTO #Data
([Id], [Subject], [Value])
VALUES
(1, '801', 1),
(2, '801', 2),
(3, '801', 2),
(4, '801', 2),
(5, '801', 1),
(6, '801', 2),
(7, '801', 2),
(8, '801', 2)
Statement:
;WITH ChangesCTE AS (
SELECT
*,
CASE
WHEN LAG([Value]) OVER (PARTITION BY [Subject] ORDER BY [Id]) <> [Value] THEN 1
ELSE 0
END AS [Change]
FROM #Data
), GroupsCTE AS (
SELECT
*,
SUM([Change]) OVER (PARTITION BY [Subject] ORDER BY [Id]) AS [GroupID]
FROM ChangesCTE
)
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY [GroupID] ORDER BY [Id]) AS Rn
FROM GroupsCTE
Result:
--------------------------------------
Id Subject Value Change GroupID Rn
--------------------------------------
1 801 1 0 0 1
2 801 2 1 1 1
3 801 2 0 1 2
4 801 2 0 1 3
5 801 1 1 2 1
6 801 2 1 3 1
7 801 2 0 3 2
8 801 2 0 3 3
As per my understanding, you need DENSE_RANK as you are looking for the row number will only change when value changed. The syntax will be as below-
WITH your_table(your_column)
AS
(
SELECT 2 UNION ALL
SELECT 10 UNION ALL
SELECT 2 UNION ALL
SELECT 11
)
SELECT *,DENSE_RANK() OVER (ORDER BY your_column)
FROM your_table

How to return one record if all the records for one key meet a condition? [duplicate]

This question already has answers here:
SQL: How do you select only groups that do not contain a certain value?
(3 answers)
Closed 4 years ago.
I'm looking for a way to handle the following scenario. I have a database table which I need to return only one record only if all records for that document meet a condition.
I got this table:
Docnum Qty
220 1
220 1
220 1
220 10
221 1
221 0
221 0
221 10
222 1
222 1
222 1
222 10
The query result must returns only those records where all qty be different to zero, in this case "docnum" 220 and 222:
Docnum
220
222
Using NOT IN
select distinct Docnum
from yourTable
where Docnum not in (select Docnum from yourTable where Qty = 0)
You could use conditional aggregation:
SELECT docnum
FROM table
GROUP BY docnum
HAVING SUM(CASE WHEN Qty = 0 THEN 1 ELSE 0 END) = 0;
DBFiddle Demo
Why not use not exists
select distinct t.Docnum
from table t
where not exists (select 1 from table where Docnum = t.Docnum and Qty = 0);
select Docnum
from MyTable
group by Docnum
having min(abs(Qty)) <> 0
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE MyTable
([Docnum] int, [Qty] int)
;
INSERT INTO MyTable
([Docnum], [Qty])
VALUES
(220, 1),
(220, 1),
(220, 1),
(220, 10),
(221, 1),
(221, 0),
(221, 0),
(221, 10),
(222, 1),
(222, 1),
(222, 1),
(222, 10)
;
Query 1:
select Docnum
from MyTable
group by Docnum
having min(abs(Qty)) <> 0
Results:
| Docnum |
|--------|
| 220 |
| 222 |
Assuming that Qty is never negative:
select Docnum
from tab
group by Docnum
Having min(Qty) > 0
If it might be negative, too:
select Docnum
from tab
group by Docnum
Having min(abs(Qty)) <> 0
and a 3rd approach since the other two would work as well.
SELECT distinct docnum
FROM yourTable A
WHERE not exists (SELECT 1
FROM yourtable B
WHERE B.qty=0
and A.DocNum = B.DocNum)
This uses a correlated subquery to identify all documents where not a single record for a docNum contains a 0. It would benefit from indexes on qty and docNum.
You can use this query:
select * from "table_name" where Qty <> 0;

Pivot group multi column SQL

In SQL, how can I merge multiple columns into one column with multiple rows?
Example:
name | age | gender
------+-------+---------
John | 20 | M
Jill | 21 | F
Exam | 22 | M
I want to get this table:
Exam | John | Jill
------+-------+---------
22 | 21 | 20
M | F | M
You can do like this.
Use two PIVOT query with UNION ALL to combine them
SELECT CAST(Exam AS VARCHAR(10)) Exam,
CAST(Jill AS VARCHAR(10)) Jill,
CAST(John AS VARCHAR(10)) John
FROM
(
select age,name
from T
) as x
PIVOT
(
MAX(Age) FOR name IN ([Exam],[John],[Jill])
)AS P1
UNION ALL
SELECT Exam,Jill,John FROM
(
select name,gender
from T
) as x
PIVOT
(
MAX(gender) FOR name IN ([Exam],[John],[Jill])
)AS P1
sqlfiddle:http://sqlfiddle.com/#!18/a437d/6
You can do this using a single query -- basically unpivot and conditional aggregation:
select max(case when v.name = 'Exam' then v.val end) as exam,
max(case when v.name = 'John' then v.val end) as john,
max(case when v.name = 'Jill' then v.val end) as jill
from t cross apply
(values (t.name, cast(t.age as varchar(10)), 1),
(t.name, t.gender, 2)
) v(name, val, which)
group by which;
Here is the SQL Fiddle.
You can convert the values to whatever character type you like for compatibility among the values. You want to put numeric values and strings in the same column, so they have to have the same type.

Turn values into column names

I have one table which contains some rows as below :
Sr. Name Product Qty
1 Yogesh ALB 1
2 Suresh AMS 2
3 Yogesh ALB 2
4 Mahesh MAS 5
Now, i want display records as in below style...
Sr. Name ALB AMS MAS
1 Yogesh 3 0 0
2 Suresh 0 2 0
3 Mahesh 5 0 0
BEGIN TRAN
CREATE TABLE #temp
(
Sr Int NOT null, Name Varchar(255), Product Varchar(255) , Qty numeric
)
INSERT INTO #temp
SELECT 1 ,'Yogesh', 'ALB', 1 UNION All
Select 2 , 'Suresh','AMS',2 UNION All
Select 3 , 'Yogesh' , 'ALB',2 UNION All
Select 4 , 'Mahesh','MAS',5
SELECT NAME,ISNULL(ALB,0) AS ALB,ISNULL(AMS,0) AS AMS,ISNULL(MAS,0) AS MAS
FROM (
SELECT
(Name) as Name,left(Product,3)as Product,
Isnull(Qty,0) as Qty
FROM #temp
) as s
PIVOT (SUM(QTY) FOR PRODUCT IN (ALB, AMS, MAS)) AS pvt
ORDER BY Name
ROLLBACK TRAN
Try with the below query.
SELECT ROW_NUMBER()OVER(ORDER BY (SELECT 1)) [Sr.],Name,ISNULL(ALB,0) AS ALB,ISNULL(AMS,0) AS AMS,ISNULL(MAS,0) AS MAS
FROM (
SELECT Name,Product,
ISNULL(Qty,0) as Qty
FROM #temp
) as s
PIVOT (SUM(QTY) FOR PRODUCT IN (ALB, AMS, MAS)) AS pvt
Use
SELECT NAME,ISNULL(ALB,0) AS ALB,ISNULL(AMS,0) AS AMS,ISNULL(MAS,0) AS MAS
FROM
(SELECT NAME,PRODUCT,SUM(QTY) QTY FROM TABLENAME
GROUP BY NAME,PRODUCT) A
PIVOT(SUM(QTY) FOR PRODUCT IN (ALB,AMS,MAS)) AS PVT

For different groups, sql query to replace null value with known value from next known value

I have this SQL table which looks like this:
customer date number
--------- ---- ------
A 1 3
A 2 NULL
A 3 5
A 4 NULL
A 5 6
B 1 NULL
B 2 NULL
B 3 10
Per customer, I'm looking to add an extra column number_NEW which replaces the NULL in number (if this is null) with the next known chronologically known number (determined by date):
customer date number number_NEW
--------- ---- ------ ----------
A 1 3 3
A 2 NULL 5
A 3 5 5
A 4 NULL 6
A 5 6 6
B 1 NULL 10
B 2 NULL 10
B 3 10 10
How would I go about this in SQL?
Thanks a lot!
You can use APPLY:
SELECT
*,
Number_NEW = ISNULL(t.Number, x.Number)
FROM Test t
OUTER APPLY(
SELECT TOP 1 Number
FROM Test
WHERE
Customer = t.Customer
AND Date > t.Date
AND Number IS NOT NULL
ORDER BY Date
)x
ORDER BY t.Customer, t.Date
Your sample data is not upto the mark .
[date] column is not clear.So to be safe I have use row_number which I think is require.
Also I think your problem is already solved.I have written this script using sql 2012 with dynamic LEAD().
It not only giving correct output but also depict dynamic use of LEAD().
Declare #t table(customer varchar(20),[date] int, number int)
insert into #t values
('A', 1,3 )
,('A', 2, NULL)
,('A', 3, 5 )
,('A', 4, NULL )
,('A', 5, 6)
,('B', 1, NULL)
,('B', 2, NULL)
,('B', 3, 10)
;WITH CTE
AS (
SELECT *
,ROW_NUMBER() OVER (
PARTITION BY customer ORDER BY [DATE]
) RN
FROM #T
)
--SELECT * FROM CTE
SELECT *
,IIF(number IS NULL, LEAD(number, (
SELECT TOP 1 RN - A.RN
FROM CTE
WHERE customer = a.customer
AND RN > a.RN
AND number IS NOT NULL
ORDER BY RN
), number) OVER (
ORDER BY customer
,[date]
), number) number_NEW
FROM CTE A
alter table T add number_NEW int null;
update T /* substitute table name here -- I realize that SQL Server allows aliases */
set number_NEW =
case
when number is null
then (
select min(t2.number) /* do date and number always increase together? */
from T as t2
/* substitute full table name here as well */
where t2.customer = T.customer and t2.date > T."date"
)
else number
end
);
alter table T alter column number_NEW int not null;