How to display all but first table row? - sql

Is it possible to display all but first row from a table in sql server 2005?
I have this data:
---------------------------------
| ID | Name |
---------------------------------
| 1 | John Smith |
| 2 | John Doe |
| 3 | John Thatcher |
---------------------------------
In my query I need to be able to get 'John Doe' and 'John Thatcher'. I Don't need 'ID' column to be displayed, so I can't use ROW_NUMBER here like follows:
select Name from Customers where ROW_NUMBER() over (order by Id)>1
Please advice.
Thank you.
UPDATE:
Clarification: I would like my query to return only Name column but I can't use table expressions, because I'm using the query as part of string concatenation:
select stuff((select ', '+pfn.FullName from PlaintiffsFullNameView pfn where pfn.SuitId=s.Id for xml path('')),1,1,'') as "CoPlaintiffs"
Now I need to transform this query to return all but first plaintiff in a concatenated manner.
UPDATE 2:
Sorry for messed up explanation, let me try it anew:
I have a suits table and a plaintiffs table. (one to many)
I have a requirement to display each suit with all coplaintiffs concatenated.
"Coplaintiff" is any but first suit plaintiff. I can concatenate all plaintiffs and display them along with corresponding suit data (all in one row), but I can't to figure out how to concatenate all coplaintiffs and display them as string in a row column.

SELECT Name
FROM (
SELECT Name, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM Customers
) q
WHERE rn > 1
ORDER BY
id
Update:
From your explanation:
SELECT Suit.*,
FirstPlantiff.*,
(
SELECT cp.Name AS [text()]
FROM Plantiff cp
WHERE cp.id <> FirstPlantiff.id
AND cp.SuitID = Suid.ID
ORDER BY
cp.id
FOR XML PATH('')
) AS Coplantiffs
FROM Suit
CROSS APPLY
(
SELECT TOP 1 *
FROM Plantiff p
WHERE p.SuitID = Suit.ID
ORDER BY
p.id
) FirstPlantiff

SELECT Name
FROM Customers
WHERE ID <> (SELECT TOP 1 ID
FROM Customers
ORDER BY ID)
Or since the Id never changes you could just do where ID <> 1

Your query with ROW_NUMBER gives an error, because you can't use ROW_NUMBER in the WHERE clause. So you'd need another subquery:
select stuff((
select ',' + FullName
from (
select pfn.FullName, row_number() over (order by pfn.id) as rn
from #suits s
inner join #plaintiffs pfn on s.id = pfn.SuitId
) sub
where rn <> 1
for xml path('')
), 1, 1, '') subsub
Alternatively, you could select the id of the first row in a subquery:
select stuff((
select ',' + pfn.FullName
from #suits s
inner join #plaintiffs pfn on s.id = pfn.SuitId
where s.id = 1
and pfn.id not in (
select min(id) from #plaintiffs where SuitId = s.id)
for xml path('')
), 1, 1, '') sub
Here's the code segment to generate test data:
declare #suits table (id int identity, CaseName varchar(max))
insert into #suits (CaseName) values ('The People v.s. Donald Duck')
declare #plaintiffs table (id int identity,
SuitId int, FullName varchar(max))
insert into #plaintiffs (SuitId,Fullname)
select 1, 'John Smith'
union all select 1, 'John Doe'
union all select 1, 'John Thatcher'

Your query should work, there's no need for Id to be returned for it to be used in the WHERE condition.
Also, maybe this page can help.

SELECT * FROM Customers
EXCEPT SELECT TOP 1 * FROM Customers

Try these
Solution 1:
select name
from #tbl
where id <> 1
Solution 2:
select top(select count(name) -1 from #tbl) name
from #tbl
order by id desc

Related

Frequency of all combinations of values for certain column

I have a dataset in SQL Server 2012 with a column for id and value, like this:
[id] [value]
--------------
A 15
A 11
A 11
B 13
B 15
B 12
C 12
C 13
D 13
D 12
My goal is to get a frequency count of all combinations of [value], with two caveats:
Order doesn't matter, so [11,12,15] is not counted separately from [12,11,15]
Repeated values are counted separately, so [11,11,12,15] is counted separately from [11,12,15]
I'm interested in all combinations, of any length (not just pairs)
So the outcome would look like:
[combo] [frequency]
---------------------
11,11,15 1
12,13,15 1
12,13 2
I've seen answers here involving recursion that answer similar questions but where order counts, and answers here involving self-joins that yield pair-wise combinations. These come close but I'm not quite sure how to adapt for my specific needs.
You can use string_agg():
select vals, count(*) as frequency
from (select string_agg(value, ',') within group (order by value) as vals, id
from t
group by id
) i
group by vals;
SQL Server 2012 doesn't support string_agg() but you can use the XML hack:
select vals, count(*) as frequency
from (select id,
stuff( (select concat(',', value)
from t t2
where t2.id = i.id
for xml path ('')
), 1, 1, ''
) as vals
from (select distinct id from t) i
) i
group by vals;
Your number string is just all the values with the same id in increasing order. So I'm treating the lowest id as a canonical name for the full sequence and all its matches. This spares all the string manipulations though you can expand as necessary.
Just tag each duplicate value with a counter and then look for groups that pair up completely.
with data as (
select id, value,
row_number() over (partition by id, value) as rn
), matches as (
select l.id, r.id as match
from data l full outer join data r on
l.value = r.value and l.rn = r.rn and l.id <= r.id
group by l.id
having count(l.id) = count(*) and count(r.id) = count(*)
)
select id, count(match) as frequency
from matches
group by id;
The logic in the middle query is also easily adaptable for finding subset of values in common.
You can achieve this using CTEs and row_number functions.
DECLARE #table table(id CHAR(1), val int)
insert into #table VALUES
('A',15),
('A',11),
('A',11),
('B',13),
('B',15),
('B',12),
('C',12),
('C',13),
('D',13),
('D',12);
;WITH CTE_rnk as
(
SELECT id,val, row_number() over (partition by id order by val) as rnk
from #table
),
CTE_concat as
(
SELECT id, cast(val as varchar(100)) as val, rnk
from CTE_rnk
where rnk =1
union all
SELECT r.id, cast(concat(c.val,',',r.val) as varchar(100)) as val,r.rnk
from CTE_rnk as r
inner join CTE_concat as c
on r.rnk = c.rnk+1
and r.id = c.id
),
CTE_maxcombo as
(
SELECT id,val, row_number() over(partition by id order by rnk desc) as rnk
from CTE_concat
)
select val as combo, count(*) as frequency
from CTE_maxcombo where rnk = 1
group by val
+----------+-----------+
| combo | frequency |
+----------+-----------+
| 11,11,15 | 1 |
| 12,13 | 2 |
| 12,13,15 | 1 |
+----------+-----------+

SQL : How to find the count of an particular category values from an column with string values

I have a SQL Table called "category" looks like this
id | category
--------------
1 | 3,2
2 | 1
3 | 4,3,2
4 | 2,1
5 | 1,4
6 | 2,3,4
There are multiple category id's in the column "category", I need to find the count of an particular category values.
Current method I am using is:
select count(distinct(Category)) AS coldatacount from table_name
It gives the count of all the distinct values WHERE as I need to get
the count of all the particular category_id's separately.
if you are trying to get the Category Ids in comma delimited, you can use the string_split function to get distinct category_id
with cte as (
select 1 as id, '3,2' as category union all
select 2, '1' union all
select 3, '4,3,2' union all
select 4, '2,1' union all
select 5, '1,4' union all
select 6, '2,3,4'
)select count(distinct(value)) as category from cte
cross apply string_split(cte.category, ',');
I assumed that #neeraj04 may be looking for count of all Id in the category, continuing with #METAL code:
CREATE TABLE YourTable
(
Id INT IDENTITY,
[Category] VARCHAR(50)
);
INSERT YourTable VALUES ('3,2'), ('1'), ('4,3,2'), ('2,1'), ('1,4'), ('2,3,4');
SELECT CAST(value AS INT) AS category -- Value is string ouptut
, COUNT([value]) AS IdCount
FROM YourTable yt
CROSS APPLY string_split(yt.Category, ',')
GROUP BY [value]
ORDER BY category;
This is a horrible data model. You should not be storing multiple values in a string. You should not be storing numbers as strings.
Sometimes we are stuck with other people's really, really bad decisions. One approach is to split the string and count:
select t.*, cnt
from t cross apply
(select count(*) as cnt
from string_split(t.category) s
) s;
The other is to count commas:
select t.*,
(1 + len(t.category) - len(replace(t.category, ',', '')) as num_elements
Select Count(Value) from (Select Value from Table_Name a Cross Apply
string_split(a.Category, ','))ab Where Value=1

SQL - How to Order By in UNION query

Is there a way to union two tables, but keep the rows from the first table appearing first in the result set? However orderby column is not in select query
For example:
Table 1
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Table 2
name surname
------------------
Lucky Dube
Abby Arnold
Result
Expected Result:
name surname
-------------------
John Doe
Bob Marley
Ras Tafari
Lucky Dube
Abby Arnold
I am bringing Data by following query
SELECT name,surname FROM TABLE 1 ORDER BY ID
UNION
SELECT name,surname FROM TABLE 2
The above query is not keeping track of order by after union.
P.S - I dont want to show ID in my select query
I am getting ORDER BY Column by joining tables. Following is my real query
SELECT tbl_Event_Type_Sort_Orders.Appraisal_Event_Type_ID AS Appraisal_Event_Type_ID , ISNULL(tbl_Appraisal_Event_Types.Appraisal_Event_Type_Display_Name, 'UnCategorized') AS Appraisal_Event_Type_Display_Name
INTO #temptbl
FROM tbl_Event_Type_Sort_Orders
INNER JOIN tbl_Appraisal_Event_Types
ON tbl_Event_Type_Sort_Orders.Appraisal_Event_Type_ID = tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID
WHERE 1=1
AND User_Name='abc'
ORDER BY tbl_Event_Type_Sort_Orders.Sort_Order
SELECT * FROM #temptbl
UNION
SELECT DISTINCT (tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID) AS Appraisal_Event_Type_ID , ISNULL(tbl_Appraisal_Event_Types.Appraisal_Event_Type_Display_Name, 'UnCategorized') AS Appraisal_Event_Type_Display_Name
FROM tbl_Appraisal_Event_Types
INNER JOIN tbl_Appraisal_Events
ON tbl_Appraisal_Event_Types.Appraisal_Event_Type_ID = tbl_Appraisal_Events.Event_Type_ID
INNER JOIN tbl_Appraisals
ON tbl_Appraisal_Events.Appraisal_ID = tbl_Appraisal_Events.Appraisal_ID
WHERE 1=1
AND ((tbl_Appraisals.Assigned_To_Staff_User) = 'abc' OR (tbl_Appraisals.Assigned_To_Staff_User2) = 'abc' OR (tbl_Appraisals.Assigned_To_Staff_User3) = 'abc')
Put a UNION ALL in a derived table. To keep duplicate elimination, do select distinct and also add a NOT EXISTS to second select to avoid returning same person twice if found in both tables:
select name, surname
from
(
select distinct name, surname, 1 as tno
from table1
union all
select distinct name, surname, 2 as tno
from table2 t2
where not exists (select * from table1 t1
where t2.name = t1.name
and t2.surname = t1.surname)
) dt
order by tno, surname, name
You can use a column for the table and one for the ID to order by:
SELECT x.name, x.surname FROM (
SELECT ID, TableID = 1, name, surname
FROM table1
UNION ALL
SELECT ID = -1, TableID = 2, name, surname
FROM table2
) x
ORDER BY x.TableID, x.ID
You can write as below, if you are ok with duplicate data then please use UNION ALL it will be faster:
SELECT NAME, surname FROM (
SELECT ID,name,surname FROM TABLE 1
UNION
SELECT ID,name,surname FROM TABLE 2 ) t ORDER BY ID
this will order the first row sets first then by anything you need
(haven't tested the code)
;with cte_1
as
(SELECT ID,name,surname,1 as table_id FROM TABLE 1
UNION
SELECT ID,name,surname,2 as table_id FROM TABLE 2 )
SELECT name, surname
FROM cte_1
ORDER BY table_id,ID
simply use a UNION clause with out order by.
SELECT name,surname FROM TABLE 1
UNION
SELECT name,surname FROM TABLE 2
if you wanted to order first table use the below query.
;WITH cte_1
AS
(SELECT name,surname,ROW_NUMBER()OVER(ORDER BY Id)b FROM TABLE 1 )
SELECT name,surname
FROM cte_1
UNION
SELECT name,surname
FROM TABLE 2

How to update value if one of the field has multiple same values in SQL

In my database table, one of the fields has the same values. I want to change this value with random number or string which is appended to this field value for uniqueness.
Sample Data
Here 'Ma' has 5 records and so on. I want to change Name Ma01, Ma02 etc.
Id Name Count
1 Ma 5
2 Ga 6
3 Gu 5
How can do with SQL query
Try this
UPDATE TBL
SET Name = A.Name
FROM
(
SELECT
Id,
Name + CAST(ROW_NUMBER() OVER (PARTITION BY Name ORDER BY (SELECT NULL)) AS NVARCHAR(500)) AS NAME,
Count
FROM
TBL
WHERE
NAME IN
(
SELECT T.NAME FROM TBL T
GROUP BY T.NAME
HAVING COUNT(1) > 1
)
) A
WHERE
TBL.Id = A.ID
Try this:
Select Name + convert(varchar(2), row_number()over(partition by Name order by Name))
From tablename
You just try this.
Declare #i int = 1
update yourtable
set ID = #i , #i = #i + 1
Select Code based on NEER`s code with leading zero added, tested on MSSQL database.
SELECT
Id,
Name,
Name + RIGHT('00'+CAST(ROW_NUMBER() OVER (PARTITION BY Name ORDER BY (SELECT Name)) AS NVARCHAR(MAX)),2) AS Updatedname
FROM
tablename
WHERE
Name IN
(
SELECT T.NameFROM tablename T
GROUP BY T.Name
HAVING COUNT(Name) > 1
)
GROUP BY Name,Id
ORDER BY Name

Get multiple id on multiple value in string with sql?

I have one table like
tbl
---------------------
id users name
---------------------
1 2,3 acc1
2 4 acc2
3 2,4,1 acc3
4 4,1 acc4
In this table I want to get id and name by users
i.e user [2] have which id and name
Suppose I pass user [2] then i get result id is 1 and 3 and name acc1 and acc3.
Try this will work for you
SELECT id,name FROM yourtablename WHERE `users` LIKE '%2%';
You can split those comma separated values using XML functions and then search in the result :
DECLARE #table TABLE(id INT, users VARCHAR(30), name VARCHAR(30))
INSERT INTO #table VALUES
(1,'2,3','acc1'),
(2,'4','acc2'),
(3,'2,4,1','acc3'),
(4,'4,1','acc4')
SELECT t.id,
t.name,
( c1.value('.', 'varchar(100)') )
FROM (SELECT id,
name,
CAST('<N>' + REPLACE(users, ',', '</N><N>') + '</N>' AS XML)
FROM #table) t(id, name, c)
CROSS APPLY c.nodes('/N') AS t1(c1)
WHERE ( c1.value('.', 'varchar(100)') ) = '2'
Use the LIKE function
SELECT id, name
FROM yourtable
WHERE (user = '2' OR user LIKE '2,%' OR user LIKE '%,2' OR user LIKE '%,2,%')
You shouldn't store delimited values in a database, but here's a solution for you, that will normalise the data:
;WITH CTE AS (
SELECT T1.[id], T2.my_Splits AS [user], T1.[name]
FROM (
SELECT *,CAST('<X>'+replace(T.users,',','</X><X>')+'</X>' as XML) as my_Xml
FROM Table1 T
) T1
CROSS APPLY (
SELECT my_Data.D.value('.','varchar(50)') as my_Splits
FROM T1.my_Xml.nodes('X') as my_Data(D)) T2)
SELECT *
FROM CTE
WHERE [user] = 2
And a working fiddle: http://sqlfiddle.com/#!6/dcec6/1