'ß' and 'ss' being merged in group by [duplicate] - sql-server

If I execute the code below:
with temp as
(
select 'Test' as name
UNION ALL
select 'TEST'
UNION ALL
select 'test'
UNION ALL
select 'tester'
UNION ALL
select 'tester'
)
SELECT name, COUNT(name)
FROM temp
group by name
It returns the results:
TEST 3
tester 2
Is there a way to have the group by be case sensitive so that the results would be:
Test 1
TEST 1
test 1
tester 2

You need to cast the text as binary (or use a case-sensitive collation).
With temp as
(
select 'Test' as name
UNION ALL
select 'TEST'
UNION ALL
select 'test'
UNION ALL
select 'tester'
UNION ALL
select 'tester'
)
Select Name, COUNT(name)
From temp
Group By Name, Cast(name As varbinary(100))
Using a collation:
Select Name Collate SQL_Latin1_General_CP1_CS_AS, COUNT(name)
From temp
Group By Name Collate SQL_Latin1_General_CP1_CS_AS

You can use an case sensitive collation:
with temp as
(
select 'Test' COLLATE Latin1_General_CS_AS as name
UNION ALL
select 'TEST'
UNION ALL
select 'test'
UNION ALL
select 'tester'
UNION ALL
select 'tester'
)
SELECT name, COUNT(name)
FROM temp
group by name

Simply:
SELECT count(*), CAST(lastname as BINARY) AS lastname_cs
FROM names
GROUP BY lastname_cs;

In MySQL/MariaDB, if you don't want to use collations or casting to binary, just use:
SELECT MAX(name), COUNT(name)
FROM (
select 'Test' as name
UNION ALL
select 'TEST'
UNION ALL
select 'test'
UNION ALL
select 'test'
UNION ALL
select 'tester'
UNION ALL
select 'tester'
) as tmp
group by MD5(name)

This works on my case:
SELECT BINARY example FROM table GROUP BY BINARY example;

Related

Return names of tables in a case exists query

I want to check if a specific value exists in some tables in my database:
SELECT CASE WHEN EXISTS (
SELECT 1 FROM (
SELECT targetId FROM [myDatabase].[dbo].[Table1] UNION
SELECT targetId FROM [myDatabase].[dbo].[Table2] UNION
SELECT targetId FROM [myDatabase].[dbo].[Table3] UNION
SELECT targetId FROM [myDatabase].[dbo].[Table4]
)T1
WHERE T1.targetId = 'idToSearch')
THEN 1 ELSE 0 END AS flag ;
The above query returns flag = 1 if the targetId idToSearch is found in these tables.
Is it possible to return also the names of the tables that this targetId was found? For example:
flag
tableNames
1
Table1, Table2
You can use string aggregation instead of EXISTS.
Note that generally UNION ALL is more efficient than UNION, although in an EXISTS this usually makes no difference
SELECT
Flag = CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END,
TableNames = STRING_AGG(TableName, ', ')
FROM
(
SELECT TableName = 'Table1', targetId
FROM [myDatabase].[dbo].[Table1]
UNION ALL
SELECT 'Table2', targetId
FROM [myDatabase].[dbo].[Table2]
UNION ALL
SELECT 'Table3', targetId
FROM [myDatabase].[dbo].[Table3]
UNION ALL
SELECT 'Table4', targetId
FROM [myDatabase].[dbo].[Table4]
) T1
WHERE T1.targetId = 'idToSearch';
Organically you would just select the tables where that ID is found like this
SELECT tablename
FROM
(
SELECT targetId, 't1' as tablename FROM [myDatabase].[dbo].[Table1] UNION
SELECT targetId, 't2' FROM [myDatabase].[dbo].[Table2] UNION
SELECT targetId, 't3' FROM [myDatabase].[dbo].[Table3] UNION
SELECT targetId, 't4' FROM [myDatabase].[dbo].[Table4]
) T1
WHERE targetId = 'idToSearch'

SQL - Find orders with certain item combo(from another table)

I have these 3 tables - CodesetList, Rule, Order:
In the first row of the Rule table, if a client ordered any of the CODE_ID under CODESET_ID=12 and any of the CODE_ID under CODESET_ID = 7 on the same service date(DAYS_FROM_Service=0), I want to find the transaction in Order table. Ultimately, if a client orders a combination of two items(Rule table), we want to deny the order according to the rule table.
Sorry, I'm bad at explaining this.
Rule:
CodesetList(note that ABC0274 is under Codeset_ID 9 & 10 and this is expected):
Order:
-- Create CodsetList table
SELECT '7' as CODESET_ID, 'ABC0210' as CODE_ID INTO #CodesetList UNION ALL
SELECT '8','ABC0220' UNION ALL
SELECT '8','ABC0230' UNION ALL
SELECT '8','ABC0240' UNION ALL
SELECT '8','ABC0250' UNION ALL
SELECT '8','ABC0260' UNION ALL
SELECT '9','ABC0270' UNION ALL
SELECT '9','ABC0272' UNION ALL
SELECT '9','ABC0274' UNION ALL
SELECT '9','ABC0273' UNION ALL
SELECT '10','ABC0274' UNION ALL
SELECT '11','ABC0277' UNION ALL
SELECT '12','ABC0330' UNION ALL
SELECT '83','ABC5110' UNION ALL
SELECT '83','ABC5120' UNION ALL
SELECT '83','ABC5130' UNION ALL
SELECT '83','ABC5140'
-- Create Rule table
SELECT '12' as TARGET_CODESET_ID, '7' as DENIAL_CODESET_ID, '2' as DIRECTION_FROM_DOS, '0' as DAYS_FROM_Service INTO #Rule UNION ALL
SELECT '83','7','1','365' UNION ALL
SELECT '7','8','2','0' UNION ALL
SELECT '7','9','2','0'
-- Create Order table
SELECT 'C3340' as ClientID, CAST('2019-10-12' AS DATE) as Service_Date, 'ABC0210' as CODE_ID INTO #Order UNION ALL
SELECT 'C3340',CAST('2019-10-12' AS DATE),'ABC0220' UNION ALL
SELECT 'C3340',CAST('2018-10-23' AS DATE),'ABC0272' UNION ALL
SELECT 'C3340',CAST('2019-10-09' AS DATE),'ABC0220' UNION ALL
SELECT 'C7646',CAST('2019-11-07' AS DATE),'ABC5110' UNION ALL
SELECT 'C7646',CAST('2019-05-07' AS DATE),'ABC0210' UNION ALL
SELECT 'C5376',CAST('2018-12-02' AS DATE),'ABC8411' UNION ALL
SELECT 'C5376',CAST('2018-10-18' AS DATE),'ABC8411' UNION ALL
SELECT 'C5376',CAST('2018-08-06' AS DATE),'ABC8161' UNION ALL
SELECT 'C9873',CAST('2019-01-06' AS DATE),'ABC6517' UNION ALL
SELECT 'C9873',CAST('2019-01-28' AS DATE),'ABC7784' UNION ALL
SELECT 'C9873',CAST('2019-03-05' AS DATE),'ABC8110'
Here's my poor attempt.
It only addresses one of the rules (row 3 from Rule table: Target=7, Denial=8)
And it also ignores the Days_From_Service rule.
SELECT *
FROM (SELECT *
FROM #Order AS o
WHERE o.CODE_ID IN(SELECT CODE_ID FROM #CodesetList WHERE CODESET_ID=7)) AS T
INNER JOIN
(SELECT *
FROM #Order AS o
WHERE o.CODE_ID IN(SELECT CODE_ID FROM #CodesetList WHERE CODESET_ID=8)) AS D ON T.ClientID=D.ClientID AND T.Service_Date=D.Service_Date;

Inserting multiple rows in SQL?

I have WindowTable with following data :
SELECT Id FROM WindowTable WHERE OwnerRef=12
Id
----
25000
25001
25003
25004
25005
25006
25007
25008
I want to Insert 3 row per each WindowTable Row in ActionTable
Like this :
Id WindowsRef ActionName ActionName2
-----------------------------------------------
1 25000 'Add' 'E'
2 25000 'DELETE' 'H'
3 25000 'UPDATE' 'B'
4 25001 'ADD' 'E'
5 25001 'DELETE' 'H'
6 25001 'Update' 'B'
. . .
. . .
ActionTable.Id is not identity column
Or:
insert into ActionTable (Id, WindowsRe, ActionName, ActionName2)
select
isnull((select max(at.Id) from ActionTable at), 0) +
row_number() over (order by w.Id, a.Action),
w.Id, a.Action, a.Action2
from WindowsTable w
cross join
(
select 'Add' as Action, 'E' as Action2
union all select 'Delete', 'H'
union all select 'Update', 'B'
) a
UPD: Fixed misstyping. Thanks #Hua_Trung for comment
UPD2: Added ActionTable.Id generation
UPD3: Added ActionName2
Something like:
insert into ActionTable(WindowsRef, ActionName)
select id WindowsRef, 'Add'
from WindowsTable
union all
select id WindowsRef, 'DELETE'
from WindowsTable
union all
select id WindowsRef, 'UPDATE'
from WindowsTable
(Assuming ActionTable.Id is an identity column or otherwise database generated.)
To generate id values as well
insert into ActionTable(id, WindowsRef, ActionName)
select
(isnull(select max(id) from ActionTable, 0)
+ row_number() over (order by x.WindowsRef, x.ActionName)
) id,
x.WindowsRef, x.ActionName
from (
select id WindowsRef, 'Add' ActionName
from WindowsTable
union all
select id WindowsRef, 'DELETE' ActionName
from WindowsTable
union all
select id WindowsRef, 'UPDATE' ActionName
from WindowsTable
) x
one more approach using apply.Using sample data from Praveen ND
select *,row_number() over (order by id) as id from #WindowTable
cross apply
(
values('add','E'),
('delete','h'),
('update','b')
)b(action,action2)
This will help you to create the script for inserting to ActionTable
DECLARE #WindowTable TABLE (ID INT)
INSERT INTO #WindowTable VALUES
(25001),
(25003),
(25004),
(25005),
(25006),
(25007),
(25008)
SELECT 'INSERT INTO ActionTable (WindowsRe,ActionName) VALUES ('+ CAST(ID AS NVARCHAR(MAX))+',ADD)' FROM #WindowTable
UNION
SELECT 'INSERT INTO ActionTable (WindowsRe,ActionName) VALUES ('+ CAST(ID AS NVARCHAR(MAX))+',UPDATE)' FROM #WindowTable
UNION
SELECT 'INSERT INTO ActionTable (WindowsRe,ActionName) VALUES ('+ CAST(ID AS NVARCHAR(MAX))+',DELETE)' FROM #WindowTable
Note : Considering ID in ActionTable as IDENTITY.
IF ID in ActionTable is not an IDENTITY :
Try to make use of below Query :
DECLARE #WindowTable TABLE (ID INT)
INSERT INTO #WindowTable VALUES
(25001),
(25003),
(25004),
(25005),
(25006),
(25007),
(25008)
DECLARE #id INT =1;
DECLARE #id1 INT = (SELECT COUNT(*) FROM #WindowTable)
DECLARE #id2 INT = (SELECT 2 *COUNT(*) FROM #WindowTable)
SELECT 'INSERT INTO ActionTable (ID,WindowsRe,ActionName,ActionName2) VALUES ('+CAST(ROW_NUMBER() OVER(ORDER BY #id) AS NVARCHAR(MAX))+','+ CAST(ID AS NVARCHAR(MAX))+',ADD,''E'')' FROM #WindowTable
UNION
SELECT 'INSERT INTO ActionTable (ID,WindowsRe,ActionName,ActionName2) VALUES ('+CAST(#id1+ ROW_NUMBER() OVER(ORDER BY #id1) AS NVARCHAR(MAX))+','+ CAST(ID AS NVARCHAR(MAX))+',UPDATE,''B'')' FROM #WindowTable
UNION
SELECT 'INSERT INTO ActionTable (ID,WindowsRe,ActionName,ActionName2) VALUES ('+CAST(#id2+ ROW_NUMBER() OVER(ORDER BY #id2) AS NVARCHAR(MAX))+','+ CAST(ID AS NVARCHAR(MAX))+',DELETE,''H'')' FROM #WindowTable
Hope this helps
Test Data
;WITH cte_TestData(WindowsRef) AS
(
SELECT 25000 UNION ALL
SELECT 25001 UNION ALL
SELECT 25003 UNION ALL
SELECT 25004 UNION ALL
SELECT 25005 UNION ALL
SELECT 25006 UNION ALL
SELECT 25007 UNION ALL
SELECT 25008
)
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ID,
a.WindowsRef,
b.ActionName,
b.ActionName2
FROM cte_TestData a
CROSS JOIN (
SELECT 'Add' AS ActionName,'E' AS ActionName2 UNION ALL
SELECT 'DELETE','H' UNION ALL
SELECT 'UPDATE','B') b
ORDER BY a.WindowsRef
Against Actual Data
;WITH cte_TestData(WindowsRef) AS
(
SELECT Id
FROM WindowTable
WHERE OwnerRef=12
)
,cte_Action AS
(
SELECT 'Add' AS ActionName,'E' AS ActionName2 UNION ALL
SELECT 'DELETE','H' UNION ALL
SELECT 'UPDATE','B'
)
--INSERT INTO <DestinationTable>
/*
- Replace <DestinationTable> with Target Table Name
- If the destination table has data the the ID has to be incremented accordingly.
-- In that case define a variable, get MAX of that ID and add that to the below
auto generated ID to preserve the sequence.
--Better yet, use Identity column as your ID Column
*/
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS ID,
a.WindowsRef,
b.ActionName,
b.ActionName2
FROM cte_TestData a
CROSS JOIN cte_Action b
--WHERE NOT EXISTS (SELECT 1 FROM <DestinationTable> c WHERE c.WindowsRef = a.WindowsRef)
/*
Enable to ensure duplicate records are not inserted, Replace <DestinationTable> with Target Table Name
*/
ORDER BY a.WindowsRef

SQL query for displaying count if same name comes in adjacent row it should show the count else 1

I have a table tb1 with columns id,name,
if same name comes in adjacent row it should display the count count else 1
For eg:
id name
1 sam
2 jose
3 sam
4 sam
5 dev
6 jose
Result want to be
name counts
sam 1
jose 1
sam 2
dev 1
jose 1
please help.
Check out this one :(SELF JOIN)
create table #sampele(id int,name varchar(50))
insert into #sampele values(1,'sam')
insert into #sampele values(2,'jose')
insert into #sampele values(3,'sam')
insert into #sampele values(4,'sam')
insert into #sampele values(5,'dev')
insert into #sampele values(6,'jose')
select a.id,a.name,case when a.name = b.name then 2 else 1 end as cnt from
#sampele a
left outer join
#sampele b
on a.id = b.id+1
Try a combination with a sub query, "COUNT(*) OVER (PARTITION", and row_number():
--DROP TABLE #Test;
SELECT id = IDENTITY(INT,1,1), name INTO #Test FROM
(
SELECT name = 'sam' UNION ALL
SELECT 'jose' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'dev ' UNION ALL
SELECT 'dev ' UNION ALL
SELECT 'jose' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'sam ' UNION ALL
SELECT 'jose'
) a;
GO
WITH GetEndID AS (
SELECT *
, EndID =(SELECT MIN(id) FROM #Test b WHERE b.name != a.name AND b.id > a.id)
FROM #Test a
), GetCount AS
(
SELECT
*
, NameCount = COUNT(*) OVER (PARTITION BY EndID)
, OrderPrio = ROW_NUMBER() OVER (PARTITION BY EndID ORDER BY id)
FROM GetEndID
)
SELECT id, name, NameCount FROM GetCount WHERE OrderPrio = 1 ORDER BY id;
select distinct a.name,case when a.name = b.name then 2 else 1 end as cnt from
tb1 a
left outer join
tb1 b
on a.id = b.id+1
sQlfiddle
Click to see running

TSQL - Sum a union query

I have a union all query in a stored procedure.
WHat I would like to do is Sum a column and return that query to the client
How would I do this?
Malcolm
SELECT
othercol1, othercol2,
SUM(bar)
FROM
(
SELECT
othercol1, othercol2, bar
FROM
RT
UNION ALL
SELECT
othercol1, othercol2, bar
FROM
FM
) foo
GROUP BY
othercol1, othercol2
SELECT SUM(MyCol) FROM
(
SELECT ... MyCol FROM Table1
UNION ALL
SELECT ... MyCol FROM Table2
)as tbl

Resources