How to use ORDER BY CHARINDEX() along with UNION? - sql

How to use ORDER BY CHARINDEX() with UNION?
What I want is like:
select Id,Name from A where Name like '%Raspberry%'
Union
select Id,Name from B where Name like '%Raspberry%'
order by CHARINDEX('Raspberry',Name)

Common Table Expression will help you:
with cte as (
select Id,Name, CHARINDEX('Raspberry', Name) ci from #t1 where Name like '%Raspberry%'
Union
select Id,Name, CHARINDEX('Raspberry', Name) ci from #t2 where Name like '%Raspberry%'
)
select Id, Name
from cte
order by ci
SQL FIDDLE

AS you mentioned the problem is you have to select the column present in order by if you are using UNION. Try this.
select Id,Name,CHARINDEX('Raspberry',Name) as order_col
from A
where Name like '%Raspberry%'
Union
select Id,Name,CHARINDEX('Raspberry',Name) as order_col
from B
where Name like '%Raspberry%'
order by order_col

Related

Order two parts of a union independently of one another

Is it possible to do something like this:
select name from table1 order by name
union
select name from table2 order by name
I know I can do this:
select name from table1
union
select name from table2 order by name
However, I want the names from table1 to appear first. I have spent the last hour Googling this and I have go nowhere. For example, I have looked here: How to order by with union in SQL?
The query needs to be a bit more complicated:
select name
from ((select distinct name, 1 as is_1 from table1)
union
(select distinct name, 0 from table2)
) n
group by name
order by max(is_1), name;
This uses select distinct in the subqueries because that can take advantage of an index on name.
Add a "sort" field and put the union inside a subquery so you can sort after the union.
untested
select a.name
from (
select name, 1 sort
from table1
union all
select name, 2 sort
from table2
) a
order by a.sort, a.name
I changed it to union all to make it clear this approach won't do a union. You could also select the sort column if you want to see it. If you don't want duplicate names, then this approach won't work.
You need another column to sort on. UNION does not allow the individual queries to have an ORDER BY clause.
Adding in a column to sort on before name allows for it to sort the individual result sets. See my example below:
CREATE TABLE #Table1 (Name VARCHAR(50))
CREATE TABLE #Table2 (Name VARCHAR(50))
INSERT INTO #Table1 VALUES ('Bart'), ('Lisa'), ('Maggie')
INSERT INTO #Table2 VALUES ('Chris'), ('Meg'), ('Stewie')
SELECT Name, 0 AS Sort FROM #Table1
UNION
SELECT Name, 1 AS Sort FROM #Table2
ORDER BY Sort, Name

Perform a function after union of two tables

I have two tables that I want to union together then perform some math functions on the combined table.
I know how to do the math for each separate table, but throwing in a union table to go off of is out of my league.
Here's the math for one table using column header "UnitsReceived" and "AsnPsUnits"
The other table would have headers: "cUnitsReceived" and "cAsnPsUnits"
select VendName,
1-abs(((cast(sum(UnitsReceived) as decimal(5,0))) - (cast(sum(AsnPsUnits) as decimal(5,0)))) /(cast(sum(AsnPsUnits) as decimal(5,0)))) as ASNpsAcc
from VenTest2
where ID<20
group by VendName
How would I perform this function after the union of two tables?
You'll need to get the unioned tables into some table object before performing your function. This could be done using:
A Common Table Expression
with cte as (
select ID, VALUE from A
union all
select ID, VALUE from B
)
select
*
,myfunction(VALUE) as MyFunctionResult
from
cte
A temp table
select ID, VALUE into #myTempTable from A
insert into #myTempTable select ID, VALUE from B
select
*
,myfunction(VALUE) as MyFunctionResult
from
#myTempTable
A table variable
declare #myTableVariable table (ID int, VALUE decimal)
insert into #myTableVariable
select ID, VALUE from A
union all
select ID, VALUE from B
select
*
,myfunction(VALUE) as MyFunctionResult
from
#myTableVariable
A sub query
select
*
,myfunction(VALUE) as MyFunctionResult
from
(
select ID, VALUE from A
union all
select ID, VALUE from B
) mySubQuery
This will help with the subq being the union
select VendName,
1-abs(((cast(sum(UnitsReceived) as decimal(5,0))) - (cast(sum(AsnPsUnits) as decimal(5,0)))) /(cast(sum(AsnPsUnits) as decimal(5,0)))) as ASNpsAcc
from
(
select ID, UnitsReceived, AsnPsUnits from VenTest2 where ID<20
union
select ID1, UnitsReceived1, AsnPsUnits1 from VenTest1
)a
group by VendName
This is not the way, brothers:
select VendName,
1-abs(((cast(sum(UnitsReceived) as decimal(10,2))) - (cast(sum(AsnPsUnits) as decimal(10,2)))) /(cast(sum(AsnPsUnits) as decimal(10,2)))) as ASNpsAcc
from VenTest2
where ID<10
group by VendName
union
select cVendName,
1-abs(((cast(sum(cUnitsReceived) as decimal(10,2))) - (cast(sum(casnpsunits) as decimal(10,2)))) /(cast(sum(cAsnPsUnits) as decimal(10,2)))) as ASNpsAcc
from CTest
where id <10
group by cvendname

I want to retrieve max value from two column - SQL table

Please find attached image for table structure
You could try using UNION ALL for build a unique column result and select the max from this
select max(col)
from (
select col1 col
from trans_punch
union all
select col2
from trans_punch) t
You can use a common table expression to union the columns, then select the max.
;with cteUnionPunch(Emp_id, both_punch) AS
(
SELECT Emp_id, In_Punch FROM trans_punch
UNION ALL
SELECT Emp_id, Out_Punch FROM trans_punch
)
SELECT Emp_id, max(both_punch) FROM cteUnionPunch GROUP BY Emp_id
You can use apply :
select tp.Emp_id, max(tpp.Punchs)
from trans_punch as tp cross apply
( values (In_Punch), (Out_Punch) ) tpp(Punchs)
group by tp.Emp_id;

SQL Server - Sorting column based on string and number

I have a table with one column which contains combination of string and number like as shown below. I need to sort the name column in descending or ascending but the problem is when I use ORDER BY it is not sorting as expected
My query is like as shown below
SELECT * FROM test ORDER BY `name` ASC
My expected result is like as shown blow
employee1
employee2
employee3
employee6
employee6
employee10
employee11
employee12
employee17
employee82
employee100
employee111
employee129
employee299
Can anyone please help me on this
You can try below by only extracting the number part from the field
SELECT * FROM test
ORDER BY cast(replace(`name`,'employee','') as int) ASC
Please try the code below:
-- ASSUMES NUMBERS ARE IN THE LAST CHARACTER
-- WONT WORK IF NUMBER IS THERE IN THE MIDDLE
DROP TABLE IF EXISTS #data
select
Name = REPLACE(name,' ','')
,NameWithNum = REPLACE(name,' ','') + cast(object_id as varchar(100))
INTO #data
from sys.tables
SELECT
NameWithNum
,NameRemovedNumbers= SUBSTRING(NameWithNum, PATINDEX('%[0-9]%', NameWithNum), LEN(NameWithNum))
from #data
ORDER BY Name,SUBSTRING(NameWithNum, PATINDEX('%[0-9]%', NameWithNum), LEN(NameWithNum))
Since the number always in the end, you can do as
WITH CTE AS
(
SELECT 'employee1' Name
union all select 'employee2'
union all select 'employee3'
union all select 'employee6'
union all select 'employee6'
union all select 'employee10'
union all select 'employee11'
union all select 'employee12'
union all select 'employee17'
union all select 'employee82'
union all select 'employee100'
union all select 'employee111'
union all select 'employee129'
union all select 'employee299'
)
SELECT Name
FROM CTE
ORDER BY CAST(SUBSTRING(Name, PATINDEX('%[^a-z, '' '']%', Name), LEN(Name)) AS INT)
--OR PATINDEX('%[0-9]%', Name)
Or
WITH CTE AS
(
SELECT 'The First Employee 1' Name
union all select 'The Second One 2'
union all select 'Employee Number 4'
union all select 'Employee Number 3'
)
SELECT Name
FROM CTE
ORDER BY CAST(SUBSTRING(Name, PATINDEX('%[0-9]%', Name), LEN(Name)) AS INT)
Here is a Live Demo where you can change the strings and see the results.
Finnaly, I would note to the real problem, which is a table with just one column and no PK.
The "base" part of the name is the same. So, you can order by the length and then the name:
SELECT t.*
FROM test t
ORDER BY LEN(name), name;

On SQL request by column

I have different simple SQL request that return only one value. Example
SELECT COUNT(*) FROM Person
OR
SELECT COUNT(*) FROM Category
I would to get all these infos in a unique request, with a column by request...
I tried something like that but it doesn't work :
SELECT COUNT(C.CategoryId) As nbPeople, COUNT(P.PersonID) As nbCategories FROM Category C, Person P
This works but I get only one column, and a row by request
SELECT COUNT(*) FROM Person UNION SELECT COUNT(*) FROM Category
How Can I simply do that ?
Thanks
When using SQL Server, you can try this:
SELECT ( select COUNT(C.CategoryId)
from Category C
) As nbPeople
, ( select COUNT(P.PersonID)
from Person P
) As nbCategories
In Oracle for example, you need to add this at the bottom
FROM dual
You can use UNION ALL like following:
SELECT '' AS [StatisticName], 1 AS [StatisticCount]
WHERE 1=0
UNION ALL
SELECT 'PersonCount', COUNT(*) FROM [Person]
UNION ALL
SELECT 'CathegoryCount', COUNT(*) FROM [Category]
First select with WHERE 1=0 is for create column header names only and is not necessary.
Try this.
select * from
(select count(*) cnt1
from Table1) t1
join
(select count(*) as cnt2
from Table2) t2 on 1=1