Merge 2 rows into one row - c#

I have this query :
Select ID, Groucode
from mytable
which returns this result:
ID GroupCode
---------------
60 00
60 01
70 00
80 00
80 01
90 00
What I want is to shows only the rows with '00' and '01', like this:
ID GroupCode
---------------
60 00
60 01
80 00
80 01

We can use aggregation here:
WITH cte AS (
SELECT ID
FROM mytable
WHERE GroupCode IN ('00', '01')
GROUP BY ID
HAVING COUNT(DISTINCT GroupCode) = 2
)
SELECT *
FROM mytable
WHERE ID IN (SELECT ID FROM cte);
Demo
Note that if the GroupCode column is really numeric, then displaying your data as 00 and 01 is not reflective of the underlying data, because SQL Server will really just treat those values as 0 and 1. In that case, you may modify my above query slightly.

I am a fresher to SQL Server , Please find my answer for above mentioned concept and you can make me correct if i am wrong .
Select mytable.* from mytable
inner join
(select id from mytable group by id having count(id)>1) as table2 on mytable.id = table2.id

Related

Dynamic Left join 2 datatable

I have 2 C# datatable:
Datatable A:
id
Name
Age
Height
01
Pauls
22
170
02
Sam
20
175
03
Mike
20
175
04
Jame
23
180
Datatable B:
id
Height
Age
01
175
23
02
190
21
The question here is how could I get this output by join 2 table A & B by id and get output datatable using Linq in C# OutputTable:
id
Name
Age
Height
01
Pauls
23(value in table B)
175 (value in table B)
02
Sam
21(value in table B)
190 (value in table B)
03
Mike
20
175
04
Jame
23
180
My code here:
var results = from ta in tableA.AsEnumerable()
join tb in tableB.AsEnumerable on ta["id"] equals tb["id"]
select new
{
ta["id"],
ta["Name"],
tb["Age"],
tb["Height"]
};
My output so far (not what I expected):
id
Name
Age
Height
01
Pauls
23(value in table B)
175 (value in table B)
02
Sam
21(value in table B)
190 (value in table B)
P/s: above table is just an example data, true data is bigger
INNER JOIN works as filter if record not found on the right side. You have to use LEFT JOIN here, which is implemented in LINQ as GroupJoin with SelectMany:
var results = from ta in tableA
join tb in tableB on ta.id equals tb.id into g
from tb in g.DefaultIfEmpty()
select new
{
ta.id,
ta.Name,
Age = tb != null ? tb.Age : ta.Age,
Height = tb != null ? tb.Height : ta.Height,
};
Could you try something like this:
var results = from ta in tableA
join tb in tableB on ta.id equals tb.id into gj
from subTableA in gj.DefaultIfEmpty()
select new
{
id = ta.id,
Name = ta.Name,
Age = (subTableA == null ? ta.Age : tb.Age + "(value in table B)"),
Height = (subTableA == null ? ta.Height : tb.Height + "(value in table B)")
};
Here is some page about left join using Entity Framework - https://learn.microsoft.com/en-us/dotnet/csharp/linq/perform-left-outer-joins
Idea is to introduce row 'from subTableA in gj.DefaultIfEmpty()' in order to get all rows from the join, even those which don't have matching value in second table.
If I understand the question correctly, you want to get back a DataTable from your LINQ query. However, LINQ returns an IEnumerable<T> or an IQueryable<T> if you're querying a database.
If you want a DataTable, you'll need some additional code. I suggest you refer to the top answer on this StackOverflow question, which provides a solution for converting an IEnumerable to a DataTable.

Merge Three Tables and get one output using SQL query

I have below candidate table details
Table_TraineeInfo
TraineeID BatchId Name Mobile
--------------------------------------------------
243 45 demo201 9888562341
244 45 demo202 9888562342
246 45 demo204 9888562344
This is my batch details of above candidate have reference id 45 in both common tables
Table_Batch_Lookup
BatchId BatchStartDate BatchEndDate
------------------------------------------------------------------------
45 2019-11-27 00:00:00.000 2019-11-29 23:59:59.000
Below is my Trainee attendance log table have common between Table_TraineeInfo and Table_Attendance_Log is TraineeID
Table_Attendance_Log
TraineeID BatchId Attendance Date
------------------------------------------------------------
243 45 Present 2019-11-27 17:55:56.513
243 45 Present 2019-11-28 17:58:06.220
243 45 Absent 2019-11-29 18:00:56.820
244 45 Present 2019-11-29 18:05:03.930
246 45 Absent 2019-11-28 18:09:08.567
246 45 Present 2019-11-29 18:09:08.567
I want output like below merge the three tables and get one output as batch candidate attendance report using a SQL query or possible way.
TraineeID BatchId Name Mobile 2019-11-27 2019-11-28 2019-11-29 Score
-----------------------------------------------------------------------------------------------------------------------------
243 45 demo201 9888562341 Present Present Absent 3/2
244 45 demo202 9888562342 No Record No Record Present 3/1
246 45 demo204 9888562344 No Record Absent Present 3/1
I will explain above output first four columns will fill using Table_TraineeInfo and next dataes will fill base on BatchStartDate and BatchEndDate from Table_Batch_Lookup and
Present and absent will base on Table_Attendance_Log no data availabe in attendacne list then fill no record, finally score Present will 1 value and out of 3 days.
I'm not sure how close to solution it but you may need dynamic pivot.
please try below:
CREATE TABLE Table_TraineeInfo (TraineeID int,BatchId int,Name varchar(max),Mobile varchar(10))
INSERT INTO Table_TraineeInfo VALUES(243, 45 , 'demo201' , '9888562341')
INSERT INTO Table_TraineeInfo VALUES(244, 45 , 'demo202' , '9888562342')
INSERT INTO Table_TraineeInfo VALUES(246, 45 , 'demo204' , '9888562344')
CREATE TABLE Table_Attendance_Log (TraineeID INT, BatchId INT, Attendance VARCHAR(10) , l_date DATETIME)
INSERT INTO Table_Attendance_Log VALUES (243, 45 , 'Present' ,'2019-11-27 17:55:56.513')
INSERT INTO Table_Attendance_Log VALUES (243, 45 , 'Present' ,'2019-11-28 17:58:06.220')
INSERT INTO Table_Attendance_Log VALUES (243, 45 , 'Absent' ,'2019-11-29 18:00:56.820')
INSERT INTO Table_Attendance_Log VALUES (244, 45 , 'Present' ,'2019-11-29 18:05:03.930')
INSERT INTO Table_Attendance_Log VALUES (246, 45 , 'Absent' ,'2019-11-28 18:09:08.567')
INSERT INTO Table_Attendance_Log VALUES (246, 45 , 'Present' ,'2019-11-29 18:09:08.567')
CREATE TABLE Table_Batch_Lookup (BatchId int , BatchStartDate DATETIME , BatchEndDate DATETIME)
INSERT INTO Table_Batch_Lookup VALUES( 45 , '2019-11-27 00:00:00.000', '2019-11-29 23:59:59.000')
Date CTE
Declare #cols NVARCHAR(Max)='';
;With log_date AS (
SELECT BatchStartDate as l_date FROM Table_Batch_Lookup
UNION ALL
SELECT DATEADD(dd, 1, l_date) FROM log_date AS ld , Table_Batch_Lookup AS tb WHERE ld.l_date<DATEADD(dd, -1, tb.BatchEndDate)
)
SELECT #cols = COALESCE (#cols + ',[' + CONVERT(NVARCHAR,CONVERT(VARCHAR(10), l_Date, 111), 106) + ']','[' + CONVERT(NVARCHAR, l_Date, 106) + ']') FROM (SELECT DISTINCT CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM log_date) PV;
Dynamic Pivot
Declare #totalScore INT =len(#cols) - len(replace(#cols, ',', ''))
CREATE TABLE #scoreTable (TraineeID int,Score Varchar(max))
INSERT INTO #scoreTable SELECT TraineeID,(CAST (#totalScore AS VARCHAR(10)) +'/'+CAST (SUM(CASE WHEN Attendance='Present' THEN 1 ELSE 0 END) AS VARCHAR(10)))AS Score from Table_Attendance_Log GROUP BY TraineeID;
--SELECT * from #scoreTable
DECLARE #query NVARCHAR(MAX);
SET #query = 'SELECT t_info.TraineeID,t_batch.BatchId,t_info.Name,t_info.Mobile'+#cols+' ,s.Score FROM Table_TraineeInfo AS t_info JOIN
(SELECT * FROM
(
SELECT TraineeID,BatchId,Attendance,CONVERT(VARCHAR(10), l_Date, 111) AS l_date FROM Table_Attendance_Log
) x
PIVOT
(
MAX(Attendance)
FOR l_Date IN (' + right(#cols, len(#cols)-1)+ ')
) p ) AS f_pv ON t_info.TraineeID=f_pv.TraineeID
JOIN Table_Batch_Lookup as t_batch ON t_batch.BatchId=t_info.BatchId
JOIN #scoreTable AS s ON t_info.TraineeID=s.TraineeID
WHERE t_batch.BatchId=45;
' ;
EXEC SP_EXECUTESQL #query;
output:
TraineeID BatchId Name Mobile 2019/11/27 2019/11/28 2019/11/29 Score
243 45 demo201 9888562341 Present Present Absent 3/2
244 45 demo202 9888562342 Present 3/1
246 45 demo204 9888562344 Absent Present 3/1
Demo
Impossible to create one query with different column count and column
names.
The workaround is creating a script for dynamic SQL query forming. Or I can write a query with columns named [day1],[day2],...,[dayN]...
if between BatchEndDate and BatchStartDate always the same day's count.

Get data from SQLServer in ASC order

I have a table with column name id and value. While data is being saved in sql server database, it sorts itself in random order, i.e id value 1,2,3,4,5,6,7,14,15,16,17,8,9,10 and likewise.
I need to retrieve data in 4 groups with each having 11 data in asc id order,
that is,
Group 1: 1-11
Group 2 : 12-22
Group 3 : 23-33
Group 4 : 33-44
I have tried query
Group 1:select top(11) * from tblCode order by id ASC
Group 2:SELECT top(22)* FROM tblCode except select top(11) * from tblCode order by id ASC
Group 3:SELECT top(33)* FROM tblCode except select top(22) * from tblQRCode order by id ASC
group 4:SELECT top(44)* FROM tblCode except select top(33) * from tblCode order by id ASC
What my problem is since data are sorted randomly while saving them into database, they are retrieved randomly.
Below is the screenshot of how my data are saved in database.
help me select data as above mentioned group.
Use OFFSET and FETCH rather than TOP.
E.g. Group two would be:
select *
from tblCode
order by id ASC
offset 11 rows
fetch next 11 rows only
Complete repro script:
declare #t table (ID int not null, Value varchar(93) not null);
;With Numbers as (
select ROW_NUMBER() OVER (ORDER BY so1.object_id) as n
from sys.objects so1,sys.objects so2,sys.objects so3
)
insert into #t (ID,Value)
select n,'PEC-' + CONVERT(varchar(93),n)
from Numbers
where n between 1 and 1000
select *
from #t
order by id ASC
offset 11 rows
fetch next 11 rows only
Result:
ID Value
----------- ---------
12 PEC-12
13 PEC-13
14 PEC-14
15 PEC-15
16 PEC-16
17 PEC-17
18 PEC-18
19 PEC-19
20 PEC-20
21 PEC-21
22 PEC-22
This also get your desired results. For other queries change 33 with other values, now it get values from 33 to 22.
WITH t AS
( SELECT ROW_NUMBER() OVER (ORDER BY id) AS row_num, *
FROM tblCode )
SELECT TOP 11 *
FROM t
WHERE row_num > 33
Try this,
select * from Table Name Order by ID
I hope I am not misunderstand:
--Group 1
SELECT *
FROM tblCode
WHERE id >= 1
AND id <= 11
ORDER BY id ASC
--Group 2
SELECT *
FROM tblCode
WHERE id >= 12
AND id <= 22
ORDER BY id ASC
--Group 3
SELECT *
FROM tblCode
WHERE id >= 23
AND id <= 33
ORDER BY id ASC
You can also save the increments in variable. Maybe something like this (i.e) you send param group no 3:
--Group 3
SELECT #Group = 3 --just for sample, param should sent From application
SELECT #lastIndex = 3*11
SELECT #indexStart = #lastIndex - 10
SELECT *
FROM tblCode
WHERE id >= #indexStart
AND id <= #lastIndex
ORDER BY id ASC

Is there any way to get column value on the basis of row number?

I have a table valued function [dbo].GetValues() in my SQL Server database which is written in C#. This function returns a table of integers inside the text specified in the arguments. For example, [dbo].GetValues('232dasdg34vb3') will return following table:
| Ints |
| ---- |
| 232 |
| 34 |
| 3 |
Now I am trying to use this resultant table in a WHILE loop:
DECLARE #IntCount int = (SELECT COUNT(*) FROM [dbo].GetValues('232dasdg34vb3'))
WHILE(#IntCount > 0)
BEGIN
-- What to do here??
SET #IntCount = #IntCount - 1
END
So, is there any way I can access the rows one by one in this while loop using some index or row number?
Also, please note that I don't have access to the source code of GetValues().
UPDATE (Actual Problem)
There are three tables in database A1, A2 and A3. All of these tables has a column [ID] that is foreign key to other table in following way:
[A1].[ID] is connected to [A2].[A1ID]
[A2].[ID] is connected to [A3].[A2ID]
The text passed as argument to the function contains integers that are the [ID]s of A3 table. Now, I want the rows from A1 and A2 table using the [ID] of A3 table.
I now have all the options suggested by you people including cursors and joins. But which one is more optimized for this situation and how to do it?
EDIT:
select *
from A1
join A2 on [A1].[ID] = [A2].[A1ID]
join A3 on [A2].[ID] = [A3].[A2ID]
join [dbo].GetValues('232dasdg34vb3') V on A3.ID = v.Ints
You can use a cursor:
DECLARE #i INT
DECLARE cur CURSOR FAST_FORWARD READ_ONLY FOR
SELECT Ints FROM [dbo].GetValues('232dasdg34vb3')
OPEN cur
FETCH NEXT FROM cur INTO #i
WHILE ##FETCH_STATUS = 0
BEGIN
/* cursor logic -- #i will hold 232, then 34, then 3 */
FETCH NEXT FROM cur INTO #i
END
CLOSE cur
DEALLOCATE cur
If you have those IDs in another table you can just join on result of calling table valued function:
select * from SomeTable st
join [dbo].GetValues('232dasdg34vb3') ft on st.SomeID = ft.Ints
If you just need to select some records, a simple select can do the job:
DECLARE #Value VARCHAR(Max) = '232dasdg34vb3'
SELECT A1.Id, A2.Id
FROM A1
JOIN A2 ON A1.Id = A2.A1Id
JOIN A3 ON A2.Id = A3.A2Id
WHERE EXISTS (
SELECT 1
FROM [dbo].GetValues( #Value ) x
WHERE x.Ints = A3.Id
)
Don't use loops or cursors but set based approaches like:
SELECT x.Ints, ot.ID, ot.*
FROM OtherTable ot
WHERE ot.ID IN (SELECT x.Ints FROM [dbo].GetValues('232dasdg34vb3'))

How to find consecutive data in SQL

I have the following data in a SQL Table:
I want to find 3 Consecutive data by No and group with ID. Result are
How to write query.please help.
Here is query which select only rows where actually 3 consecutive rows are:
SELECT a.*
FROM
TABLE as a
inner join
TABLE as b on (a.no+1=b.no and a.id=b.id)
inner join
TABLE as c on (a.no+2=c.no and a.id=c.id)
order by a.id, a.no
for your data it will provide:
4 a1 4
5 a1 3
1 a2 2
2 a2 4
3 a3 2
4 a3 3
rows (6,a1,1), (3,a2,5) and (5,a3,4) are not selected, as there are no (8,a1) (5,a2) and (7,a3)
DECLARE #temp TABLE (NO int,ID VARCHAR(2),QTY int)
INSERT INTO #temp
SELECT 1,'A1',5 UNION ALL
SELECT 4,'A1',4 UNION ALL
SELECT 5,'A1',3 UNION ALL
SELECT 6,'A1',1 UNION ALL
SELECT 7,'A1',0 UNION ALL
SELECT 9,'A1',5 UNION ALL
SELECT 12,'A1',3 UNION ALL
SELECT 1,'A2',2 UNION ALL
SELECT 2,'A2',4 UNION ALL
SELECT 3,'A2',5 UNION ALL
SELECT 4,'A2',1 UNION ALL
SELECT 7,'A2',4 UNION ALL
SELECT 9,'A2',5 UNION ALL
SELECT 1,'A3',0 UNION ALL
SELECT 3,'A3',2 UNION ALL
SELECT 4,'A3',3 UNION ALL
SELECT 5,'A3',4 UNION ALL
SELECT 6,'A3',2;
WITH tmpa AS
(
SELECT *
, NO - ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID) AS grp
FROM #temp
)
, tmpb AS
(
SELECT *
, COUNT(*) OVER(PARTITION BY ID,grp) AS grpcount
FROM tmpa
)
SELECT NO,ID,QTY FROM tmpb WHERE grpcount>1;
Result are
4 A1 4
5 A1 3
6 A1 1
7 A1 0
1 A2 2
2 A2 4
3 A2 5
4 A2 1
3 A3 2
4 A3 3
5 A3 4
6 A3 2
I found this query from this link.
Find ā€œnā€ consecutive free numbers from table
http://sqlfiddle.com/#!1/a2633/2
Answer Credit by

Categories

Resources