How to show specific 2 rows at the top without order and then sort the rest by order using SQL DISTINCT, UNION - sql-server

I have a country table with Id, Name with duplicate records. I am Using DISTINCT and UNION to show particular 2 country names Ireland and England at the top and rest all after By order name like below in SQL server
create table country (id int , name varchar(50));
insert into country (id, name) values( 1, 'Kuwait');
insert into country (id, name) values( 2, 'Australia');
insert into country (id, name) values( 3, 'Canada');
insert into country (id, name) values( 4, 'spain');
insert into country (id, name) values( 5, 'Turkey');
insert into country (id, name) values( 6, 'Ireland');
insert into country (id, name) values( 7, 'England');
insert into country (id, name) values( 1, 'Kuwait');
insert into country (id, name) values( 2, 'Australia');
insert into country (id, name) values( 3, 'Canada');
insert into country (id, name) values( 4, 'spain');
insert into country (id, name) values( 5, 'Turkey');
insert into country (id, name) values( 6, 'Ireland');
insert into country (id, name) values( 7, 'England');
DESIRED OUTPUT:
id name
-----------
6 Ireland
7 England
2 Australia
3 Canada
1 Kuwait
4 Spain
5 Turkey
Tried with DISTINCT & UNION in SQL QUERY:but names are not ordered after 3 row
select distinct id,name from country where id in (6,7)
union
select distinct id,name from country where id not in (6,7)
id name
-----------
6 Ireland
7 England
1 Kuwait
2 Australia
3 Canada
4 Spain
5 Turkey `
also tried with ORDER BY CASE:
select distinct id,name from country where id in (6,7)
union
select distinct id,name from country where id not in (6,7)
ORDER BY CASE
WHEN id = 6 and id = 7 -- whatever identifies that row
THEN 1 ELSE 2 END
ERROR:ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.

There is absolutely no guaranteed order of the returned result, unless order by is specified. Even if you find a query, that returned the rows in the desired order, on next run, tomorrow, or at client's site, it will not return them in the same order. So you must add an order by clause. You need to sort on some artificial values, like this:
declare #country table(id int , name varchar(50));
insert into #country (id, name) values( 1, 'Kuwait');
insert into #country (id, name) values( 2, 'Australia');
insert into #country (id, name) values( 3, 'Canada');
insert into #country (id, name) values( 4, 'spain');
insert into #country (id, name) values( 5, 'Turkey');
insert into #country (id, name) values( 6, 'Ireland');
insert into #country (id, name) values( 7, 'England');
insert into #country (id, name) values( 1, 'Kuwait');
insert into #country (id, name) values( 2, 'Australia');
insert into #country (id, name) values( 3, 'Canada');
insert into #country (id, name) values( 4, 'spain');
insert into #country (id, name) values( 5, 'Turkey');
insert into #country (id, name) values( 6, 'Ireland');
insert into #country (id, name) values( 7, 'England');
select id, name from (
select distinct id, name
from #country) t
order by case name when 'Ireland' then 'aaaaaaaaaaaaaaaaaaaaaaaa1' when 'England' then 'aaaaaaaaaaaaaaaaaaaaaaaa2' else name end

Related

Stored procedure to insert concatenated string into table

I have two tables, ParentPayor and ChildPayor.
ParentID is the primary key in ParentPayor and ParentID is a foreign key in the ChildPayor table. The ChildPayor table has a column State.
I would like to create a stored procedure that concatenates each State in the ChildPayor table, and inserts the string into the ParentPayor column States, where ChildPayor.ParentID = ParentPayor.ParentID.
I just discovered STRING_AGG to concatenate:
STRING_AGG (State, ',')
FROM ChildPayors AS States
WHERE ParentPayorID = 32
But I would like to be able to concatenate all States within the ChildPayor, and insert into ParentPayor where the ParentIDs match. Does this make sense?
Something like (I know this is incorrect):
SELECT STRING_AGG (State, ',')
FROM ChildPayors, ParentPayors AS States
WHERE ParentPayors.ParentPayorID = ChildPayors.ParentPayorID
INSERT INTO ParentPayors(States)
VALUES (States)
I will often use CROSS APPLY to calculate intermediate values. Try something like:
DECLARE #ParentPayor TABLE (ParentID INT, ParentName VARCHAR(100), States VARCHAR(1000))
INSERT #ParentPayor
VALUES
(1, 'AAA', null),
(2, 'BBB', null),
(3, 'CCC', null),
(4, 'DDD', null)
DECLARE #ChildPayor TABLE (ChildID INT, ParentID INT, StateName VARCHAR(100))
INSERT #ChildPayor
VALUES
(1, 1, 'New York'),
(2, 2, 'Texas'),
(3, 2, 'Virginia'),
(4, 2, 'California'),
(5, 4, 'Virginia'),
(6, 4, 'New York')
UPDATE P
SET States = S.States
FROM #ParentPayor P
CROSS APPLY (
SELECT States = STRING_AGG(C.StateName, ', ') WITHIN GROUP(ORDER BY C.StateName)
FROM #ChildPayor C
WHERE C.ParentID = P.ParentID
) S
SELECT *
FROM #ParentPayor P
Output:
ParentID
ParentName
States
1
AAA
New York
2
BBB
California, Texas, Virginia
3
CCC
(null)
4
DDD
New York, Virginia
The UPDATE statement above would then become the body of your stored procedure.
On further reflection, a subselect could also be used. The following JOIN could be used in place of the CROSS APPLY:
LEFT JOIN (
SELECT C.ParentID, States = STRING_AGG(C.StateName, ', ') WITHIN GROUP(ORDER BY C.StateName)
FROM #ChildPayor C
GROUP BY C.ParentID
) S ON S.ParentID = P.ParentID

How check if specific record exist in table or not

I have a table in which I have multiple dates stored which are the attendance dates of employee
CREATE TABLE Attendance
(
EmpCode INT,
AttendanceDate DATETIME
)
INSERT INTO Attendance VALUES (24, '2018-12-01');
INSERT INTO Attendance VALUES (24, '2018-12-02');
INSERT INTO Attendance VALUES (24, '2018-12-03');
INSERT INTO Attendance VALUES (24, '2018-12-04');
INSERT INTO Attendance VALUES (24, '2018-12-06');
Now as there is not date saved for this employee on 5th Dec it should show Absent in that case.
SELECT * FROM Attendance
It will give missed date for that emp from table if you want to insert you can insert by using existing code
CREATE TABLE #Attendance
(
EmpCode INT,
AttendanceDate DATETIME
)
INSERT INTO #Attendance VALUES (24, '2018-12-01');
INSERT INTO #Attendance VALUES (24, '2018-12-02');
INSERT INTO #Attendance VALUES (24, '2018-12-03');
INSERT INTO #Attendance VALUES (24, '2018-12-04');
INSERT INTO #Attendance VALUES (24, '2018-12-06');
select * from #Attendance
;WITH CTE AS
(
SELECT CONVERT(DATE,'2018-12-01') AS DATE1
UNION ALL
SELECT DATEADD(DD,1,DATE1) FROM CTE WHERE DATE1<'2018-12-06'
)
--insert into #Attendance(EmpCode,AttendanceDate)
SELECT DATE1 MISSING_ONE,'a' FROM CTE
EXCEPT
SELECT AttendanceDate,'a' FROM #Attendance
option(maxrecursion 0)

SQL Server query help - Related hashtags

I have been racking my brains on this one for some time, so through it was about time to ask for some help.
I have a product database, each product has a number of hashtags associated with it. I want to be able to pull out related hashtags.
Let me take you through an example:
CREATE TABLE #Test (ProductID int, Hashtag varchar(30))
INSERT INTO #Test VALUES( 1 ,'toys')
INSERT INTO #Test VALUES( 1 ,'lego')
INSERT INTO #Test VALUES( 1 ,'construction')
INSERT INTO #Test VALUES( 2 ,'toys')
INSERT INTO #Test VALUES( 2 ,'lego')
INSERT INTO #Test VALUES( 2 ,'lego-city')
INSERT INTO #Test VALUES( 3 ,'clothing')
INSERT INTO #Test VALUES( 3 ,'womens')
INSERT INTO #Test VALUES( 3 ,'jeans')
INSERT INTO #Test VALUES( 4 ,'clothing')
INSERT INTO #Test VALUES( 4 ,'mens')
INSERT INTO #Test VALUES( 4 ,'tops')
INSERT INTO #Test VALUES( 4 ,'t-shirts')
INSERT INTO #Test VALUES( 5 ,'clothing')
INSERT INTO #Test VALUES( 5 ,'mens')
INSERT INTO #Test VALUES( 5 ,'tops')
INSERT INTO #Test VALUES( 5 ,'vests')
What I want to be able to do is select a Hashtag, for example "toys", then pull out all other hashtags that have a relationship (via the productId).
This is the results set that should be returned when querying "toys":
hashtag, count
lego, 2
construction, 1
lego-city, 1
Any help or ideas on how to go about implementing this would be much appreciated.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table YourTable
(
Product_id int,
hashtag varchar(25)
)
insert into YourTable values
( 1, 'toys '),
( 1, 'lego '),
( 1, 'construction '),
( 2, 'toys '),
( 2, 'lego '),
( 3, 'lego '),
( 2, 'lego-city ')
Query 1:
select T1.hashtag,
count(*) as [count]
from YourTable as T1
where exists (
select *
from YourTable as T2
where T2.hashtag = 'toys' and
T1.Product_id = T2.Product_id
) and
T1.hashtag <> 'toys'
group by T1.hashtag
Results:
| HASHTAG | COUNT |
|---------------|-------|
| construction | 1 |
| lego | 2 |
| lego-city | 1 |
try this
select hashtag,count(hashtag) as count from #product_hashtags group by hashtag
CREATE TABLE #Test (ProductID int, Hashtag varchar(30))
INSERT INTO #Test VALUES( 1 ,'toys')
INSERT INTO #Test VALUES( 1 ,'lego')
INSERT INTO #Test VALUES( 1 ,'construction')
INSERT INTO #Test VALUES( 2 ,'toys')
INSERT INTO #Test VALUES( 2 ,'lego')
INSERT INTO #Test VALUES( 2 ,'lego-city')
SELECT * FROM #Test
SELECT * FROM (
SELECT Hashtag, COUNT(ProductID) Counter FROM #Test
GROUP BY Hashtag) as x
where x.Hashtag <> 'toys'
Is this what you want?
Use the query below:
SELECT Hashtag, COUNT(Hashtag)
FROM #Test
WHERE ProductID IN (SELECT ProductID FROM #Test WHERE Hashtag = 'toys')
AND Hashtag <> 'toys'
GROUP BY Hashtag

How do I get only the numeric values in SQL Server (ISNUMERIC not giving correct values)

I have a table called 'testTable' with two columns, 'id' that is auto incremented and 'someValue'.
The data contained in the 'someValue' column are: 12, 1.2, .4, 1d4, +, -, .
I want to select only the numeric values. But when I use the following query:
SELECT someValue, ISNUMERIC(someValue)
FROM testTable;
all the values are true. And for the query:
SELECT * FROM testTable
WHERE ISNUMERIC(someValue) = 1;
all the values are being returned.
I just want 12, 1.2 and .4 .
How can I achieve this?
UPDATE:
The data type for the column someValue is varchar(50).
SETUP:
CREATE TABLE SomeTable
(
ID INT,
Value NVARCHAR(250)
)
INSERT INTO SomeTable (ID, Value) VALUES (1, '12')
INSERT INTO SomeTable (ID, Value) VALUES (2, '1.2')
INSERT INTO SomeTable (ID, Value) VALUES (3, '.4')
INSERT INTO SomeTable (ID, Value) VALUES (4, '1d4')
INSERT INTO SomeTable (ID, Value) VALUES (5, '+')
INSERT INTO SomeTable (ID, Value) VALUES (6, '-')
INSERT INTO SomeTable (ID, Value) VALUES (7, '.')
QUERY:
SELECT * FROM SomeTable WHERE ISNUMERIC(Value+'d0')=1
RESULT:
ID VALUE
1 12
2 1.2
3 .4

Pivot in sql server

Yes I've tried the code. My requirement is that user inputs Year and Month & prices are shown date-wise in columns for that year and month, with first column as CompetitorID. I want my result like:
Competitors | day1 | day2 | day3 | day4 ..............|day31
================================================================
competitor 1| Price | Price | price | price..............|price
competitor 2| Price | Price | price | price..............|price
competitor 3| Price | Price | price | price..............|price
competitor 4| Price | Price | price | price..............|price
My Table structure is:
COMPETITORDETAIL (ID, CompetitorID, oDate, Price)
This is a lot easier. I wrote a stored proc named pivot_query that makes PIVOT a lot easier to use for SQL Server 2005+. The source for the proc is here, some examples how to use it are here.
For your code example:
create table Competitors
(
CompetitorId integer identity,
Name varchar(30)
)
insert into Competitors values ('Bobs Discount Emporium')
go
insert into Competitors values ('Joes Really Cheap Crap')
go
create table CompetitorDetail
(
Id integer identity,
CompetitorId integer,
oDate datetime,
Price decimal(12,3)
)
insert into CompetitorDetail values (1, getdate()-10, 10.00)
go
insert into CompetitorDetail values (1, getdate()-10, 10.00)
go
insert into CompetitorDetail values (1, getdate()-10, 10.00)
go
insert into CompetitorDetail values (1, getdate()-10, 10.00)
go
insert into CompetitorDetail values (1, getdate()-8, 11.00)
go
insert into CompetitorDetail values (1, getdate()-8, 11.00)
go
insert into CompetitorDetail values (1, getdate()-8, 11.00)
go
insert into CompetitorDetail values (1, getdate()-8, 11.00)
go
insert into CompetitorDetail values (1, getdate()-6, 12.00)
go
insert into CompetitorDetail values (1, getdate()-6, 12.00)
go
insert into CompetitorDetail values (1, getdate()-6, 12.00)
go
insert into CompetitorDetail values (1, getdate()-2, 13.00)
go
insert into CompetitorDetail values (1, getdate()-2, 13.00)
go
insert into CompetitorDetail values (1, getdate()-2, 13.00)
go
insert into CompetitorDetail values (2, getdate()-10, 14.00)
go
insert into CompetitorDetail values (2, getdate()-10, 14.00)
go
insert into CompetitorDetail values (2, getdate()-10, 14.00)
go
insert into CompetitorDetail values (2, getdate()-10, 14.00)
go
insert into CompetitorDetail values (2, getdate()-8, 15.00)
go
insert into CompetitorDetail values (2, getdate()-8, 15.00)
go
insert into CompetitorDetail values (2, getdate()-8, 15.00)
go
insert into CompetitorDetail values (2, getdate()-8, 15.00)
go
insert into CompetitorDetail values (2, getdate()-6, 16.00)
go
insert into CompetitorDetail values (2, getdate()-6, 16.00)
go
insert into CompetitorDetail values (2, getdate()-6, 16.00)
go
insert into CompetitorDetail values (2, getdate()-2, 18.00)
go
insert into CompetitorDetail values (2, getdate()-2, 18.00)
go
insert into CompetitorDetail values (2, getdate()-2, 18.00)
go
declare #mySQL varchar(MAX)
set #mySQL = '
select
c.Name,
right(cast(month(cd.oDate) + 100 as varchar(3)),2) + ''_'' + right(cast(day(cd.oDate) + 100 as varchar(3)),2) mon_day,
cd.Price
from
Competitors c
JOIN CompetitorDetail cd
on (cd.CompetitorId = c.CompetitorId )
';
exec pivot_query #mySQL, 'Name', 'Mon_Day', 'max(Price) MaxP,min(Price) MinP'
which results in:
Name 01_09_MaxP 01_09_MinP 01_11_MaxP 01_11_MinP 01_13_MaxP 01_13_MinP 01_17_MaxP 01_17_MinP
------------------------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------ ------------
Bobs Discount Emporium 10.000 10.000 11.000 11.000 12.000 12.000 13.000 13.000
Joes Really Cheap Crap 14.000 14.000 15.000 15.000 16.000 16.000 18.000 18.000
Hope that helps!
If you'r working with Microsoft SQL-Server there is a pivot function. But the columns are defined statically, so it's use is limited. (See http://technet.microsoft.com/en-us/library/ms177410.aspx)
There are solutions with dynamic SQL, but i solved this in the code eventually.
For SQL Server 2005, 2008
The table and some data to test
CREATE TABLE CompetitorDetail
(
ID int
,CompetitorID int
,oDate datetime
,Price decimal(19, 4)
)
INSERT INTO CompetitorDetail
( ID, CompetitorID, oDate, Price )
SELECT 1, 1, '2010-01-01', 100.0 UNION
SELECT 2, 1, '2010-01-02', 110.0 UNION
SELECT 3, 1, '2010-01-03', 99.0 UNION
SELECT 4, 2, '2010-01-01', 102.2 UNION
SELECT 5, 2, '2010-01-02', 112.2 UNION
SELECT 6, 2, '2010-01-03', 99.2 UNION
SELECT 7, 3, '2010-01-01', 100.3 UNION
SELECT 8, 3, '2010-01-02', 110.3 UNION
SELECT 9, 3, '2010-01-03', 99.3 ;
Start of the period and number of days
/* First day of the peroid */
DECLARE #StartDate datetime
,#NumberOfDays int
SET #StartDate = '2010-01-01'
SET #NumberOfDays = 31
Dynamic columns = dynamic sql
/* Table to compose dynamic query */
DECLARE #qw TABLE
(
id int IDENTITY(1, 1)
,txt nvarchar(500)
)
/* Start composing dynamic query */
INSERT INTO #qw ( txt ) VALUES ( 'SELECT' )
INSERT INTO #qw ( txt ) VALUES ( 'CompetitorID' )
Continue composing the dynamic query
/* Helpers */
DECLARE
#dte datetime
,#str varchar(10)
,#i int
/* Compose dynamic query */
SET #i = 0
WHILE #i < #NumberOfDays
BEGIN
SET #dte = DATEADD(d, #i, #StartDate)
SET #str = CONVERT(varchar(10), #dte, 121)
INSERT INTO #qw ( txt )
SELECT ',MAX(CASE oDate WHEN ''' + #str + ''' THEN Price ELSE NULL END) AS [' + #str + ']'
SET #i = #i + 1
END
/* Finish the dynamic query */
INSERT INTO #qw (txt) VALUES ( 'FROM CompetitorDetail' )
INSERT INTO #qw (txt) VALUES ( 'GROUP BY CompetitorID' )
INSERT INTO #qw (txt) VALUES ( 'ORDER BY CompetitorID' )
Concatenate into a variable and execute
/* Create a variable with dynamic sql*/
DECLARE #exe nvarchar(4000)
SET #exe=''
SELECT #exe = #exe + txt + ' ' FROM #qw ORDER BY id
/* execute dynamic sql */
EXEC sp_executesql #exe
Returns
CompetitorID 2010-01-01 2010-01-02 2010-01-03 2010-01-04 ... 2010-01-31
------------ ---------- ---------- ---------- ---------- ... ----------
1 100.0000 110.0000 99.0000 NULL ... NULL
2 102.2000 112.2000 99.2000 NULL ... NULL
3 100.3000 110.3000 99.3000 NULL ... NULL
CASE
WHEN SQL Server 2005 OR 2008 THEN Use Pivot
WHEN Oracle THEN Use LIKE MAX(Decode(Day=1,Data,0) as Day1 and GROUP BY Day
WHEN SQL Server 2000 THEN Use LIKE MAX(CASE WHEN Day = 1 THEN Data ELSE 0 End) As Day1 and GROUP BY Day
END

Resources