sql query, order by value when field matches - sql

I have data as follows:
data_id name value
-----------------------------------------
1 Address123 my street
1 Order-Date 12/23/2018
1 firstName Joe
2 Address 345 other street
2 Order-Date 12/31/2018
2 firstName Peter
...and so on..
How can I write a query to return the data ordered by 'OrderDate' using ID as the Group
e.g.
SELECT *
FROM wp_cf7_data_entry
WHERE cf7_id = 7
AND data_id IN (SELECT *
FROM (
SELECT data_id
FROM wp_cf7_data_entry
WHERE 1 = 1
AND cf7_id = 7
GROUP BY data_id
ORDER BY case
when name = 'order-date' THEN 'value'
end DESC,'data_id')
basically I want to use the subquery as the order by so results are sorted by Order-Date.

I'm guessing you want to use conditional aggregation:
select id,
max(case when name_field = 'OrderDate' then value end) as OrderDate,
max(case when name_field = 'Address' then value end) as Address,
max(case when name_field = 'Name' then value end) as Name
from yourtable
group by id
order by max(case when name_field = 'OrderDate' then value end)
This creates a single row for each id and orders the results by the order date value.

You dont need a group by as I can see for each id theres only one namefield as ordereddate
SELECT * FROM TABLE WHERE NAME_FIELD =
'OrderedDate' order by NAME_FIELD

Related

Display Column Values for last record only in sql server

Hi Iam having table like below,
Name RN AGE
A 1 21
B 2 22
C 3 23
I want to display age for last record only remaining column value as empty like below,
Name RN AGE
A 1
B 2
C 3 23
Use window function
SELECT *,
(CASE WHEN MAX(AGE) OVER () = AGE THEN CAST(AGE AS VARCHAR(10)) ELSE '' END) AGE1
FROM table
You could also use CROSS JOIN
SELECT *,
(CASE WHEN t.AGE <> c.MAXAGE THEN '' ELSE CAST(t.AGE AS VARCHAR(10)) END) AGE1
FROM table t CROSS JOIN (
SELECT MAX(AGE) AS MAXAGE FROM table) c
This assumes last records in terms of AGE else you would need to RN/Name column to be aggregate and use them.

Find Common Rows for some Row Values in SQL

I have a table with Ids and a subId column. And I have a user defined data type with a list of SubIds. I want all those ids which have all the sub-ids present in my user-defined data type. for example:
The table is:
ID SubID
1 2
1 3
1 4
2 3
2 4
2 2
3 3
3 2
and the data type is
CREATE TYPE SubIds AS TABLE
( SubId INT );
GO
With Value
SubID
3
4
I want the output to be
ID
1
2
Because only the ID 1 and 2 contain both the subIds 3 & 4
Note: the combination of Id and Sub ID will always be unique if its of any use
Let's assume that #s is your table of ids:
select t.ID
from t
Where t.SubId in (select SubId from #s)
group by t.Id
having count(*) = (select count(*) from #s);
This assumes that the two tables do not have duplicates. If duplicates are present, you can use:
select t.ID
from t
Where t.SubId in (select SubId from #s)
group by t.Id
having count(distinct t.SubId) = (select count(distinct s.SubId) from #s s);
Try this way
select ID
from yourtable
Where SubID in (3,4)
Group by ID
having Count(distinct SubID)=2
Another more flexible approach
select ID
from yourtable
Group by ID
having sum(case when SubID = 3 then 1 else 0 end) >= 1
and sum(case when SubID = 4 then 1 else 0 end) >= 1
If you want to pull SubId's from SubIds table type then,
SELECT ID
FROM yourtable T
JOIN (SELECT SubID,
Count(1) OVER() AS cnt
FROM SubIds) S
ON T.SubID = S.SubID
GROUP BY ID,Cnt
HAVING Count(DISTINCT T.SubID) = s.cnt

Count Values from Table for each type

I have the following table
UserId [nvarchar(128)], Rating [varchar(170)] :values will be mostly 1,2,3 but can have exceptions
Rating contains 3 values [1,2, or 3]
I want to get a result something like
UserId Count(1's),Count(2's) Count(3's)
1. 1001 10 8 2
2. 1002 5 10 3
Is it possible in a single query
Do a GROUP BY UserId to count for each user-id. Use CASE to count 1's, 2's and 3's separately:
select UserId,
count(case when Rating = 1 then 1 end) as [Count(1's)],
count(case when Rating = 2 then 1 end) as [Count(2's)],
count(case when Rating = 3 then 1 end) as [Count(3's)]
from tablename
group by UserId
Use a CASE statement in each COUNT and then GROUP BY UserId.
SELECT UserId, COUNT(CASE WHEN value = '1' THEN 1 END) AS [Count(1's)], COUNT(CASE WHEN value = '2' THEN 1 END) AS [Count(2's)], COUNT(CASE WHEN value = '3' THEN 1 END) AS [Count(3's)]
FROM yourtable
GROUP BY UserId
Use PIVOT:
SELECT
UserId,
COALESCE([1],0) [Count(1's)],
COALESCE([2],0) [Count(2's)],
COALESCE([3],0) [Count(3's)]
FROM
ýour_table
PIVOT
(COUNT([Rating])
FOR Rating
in([1],[2],[3])
)AS p
ORDER BY
UserId

MS SQL - One to Many Relationship - Need to return single row

I have the following tables -
Search Result
----------------
SearchResultID PK
ProductID FK
SearchQuery
WebsiteName
URL
IsFound
CreatedOn
BatchID
Name
SearchResultItem
-----------------
SearchResultItemID PK
SearchResultID FK
Name
Value
These tables have a one to many relationship, so one Search Result, can have many Search Result Items.
I can do an INNER JOIN on these tables however that obviously gives one row per each Search Result Item. Ideally I would like one row per Search Result, for example...
SearchResultID | ProductID | SearchQuery | WebsiteName | URL | IsFound |
CreatedOn | BatchID | Name | SearchResultItemID | Name 1 | Value 1 | Name 2 |
Value 2 | Name 3 | Value 3 |
Is this possible to do? And if so, can someone point me in the right direction as to how I would do this - I think it would be something like this, only in ms-sql - one to many sql select into single row - mysql
You can use the ROW_NUMBER() function to give each search result item a rank within each search result:
SELECT SearchResultItemID,
SearchResultID,
Name,
Value,
RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID)
FROM SearchResultItem;
If you have a know number of items then you can use aggregate functions to get each name/value pair:
WITH RankedItem AS
( SELECT SearchResultItemID,
SearchResultID,
Name,
Value,
RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID)
FROM SearchResultItem
)
SELECT SearchResultID,
Name1 = MIN(CASE WHEN RowNumber = 1 THEN Name END),
Value1 = MIN(CASE WHEN RowNumber = 1 then Value END),
Name2 = MIN(CASE WHEN RowNumber = 2 THEN Name END),
Value2 = MIN(CASE WHEN RowNumber = 2 then Value END),
Name3 = MIN(CASE WHEN RowNumber = 3 THEN Name END),
Value3 = MIN(CASE WHEN RowNumber = 3 then Value END),
Name4 = MIN(CASE WHEN RowNumber = 4 THEN Name END),
Value5 = MIN(CASE WHEN RowNumber = 4 then Value END)
FROM RankedItem
GROUP BY SearchResultID;
You can then join this back to your Search result table giving a full query:
WITH RankedItem AS
( SELECT SearchResultItemID,
SearchResultID,
Name,
Value,
RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID)
FROM SearchResultItem
), Items AS
( SELECT SearchResultID,
Name1 = MIN(CASE WHEN RowNumber = 1 THEN Name END),
Value1 = MIN(CASE WHEN RowNumber = 1 then Value END),
Name2 = MIN(CASE WHEN RowNumber = 2 THEN Name END),
Value2 = MIN(CASE WHEN RowNumber = 2 then Value END),
Name3 = MIN(CASE WHEN RowNumber = 3 THEN Name END),
Value3 = MIN(CASE WHEN RowNumber = 3 then Value END),
Name4 = MIN(CASE WHEN RowNumber = 4 THEN Name END),
Value4 = MIN(CASE WHEN RowNumber = 4 then Value END)
FROM RankedItem
GROUP BY SearchResultID
)
SELECT SearchResult.SearchResultID,
SearchResult.ProductID,
SearchResult.SearchQuery,
SearchResult.WebsiteName,
SearchResult.URL,
SearchResult.IsFound,
SearchResult.CreatedOn,
SearchResult.BatchID,
SearchResult.Name,
Items.Name1,
Items.Value1,
Items.Name2,
Items.Value2,
Items.Name3,
Items.Value3,
Items.Name4,
Items.Value4
FROM SearchResult
INNER JOIN Items
ON SearchResult.SearchResultID = Items.SearchResultID;
Example on SQL Fiddle
If you want to return a variable number of values then you will need to use dynamic SQL:
DECLARE #SQL NVARCHAR(MAX) = '';
SELECT #SQL = #SQL + ',[Name' + rn + '], [Value' + rn + '] '
FROM ( SELECT DISTINCT
rn = CAST(ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) AS VARCHAR)
FROM SearchResultItem
) p;
SET #SQL = 'WITH RankedItem AS
( SELECT SearchResultItemID,
SearchResultID,
Name,
Value,
RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID)
FROM SearchResultItem
), UnPivoted AS
( SELECT upvt.SearchResultID,
Name = upvt.n + CAST(RowNumber AS VARCHAR),
upvt.v
FROM RankedItem
UNPIVOT
( n
FOR v IN ([Name], [Value])
) upvt
), Pivoted AS
( SELECT *
FROM UnPivoted
PIVOT
( MAX(V)
FOR Name IN (' + STUFF(#SQL, 1, 1, '') + ')
) pvt
)
SELECT SearchResult.SearchResultID,
SearchResult.ProductID,
SearchResult.SearchQuery,
SearchResult.WebsiteName,
SearchResult.URL,
SearchResult.IsFound,
SearchResult.CreatedOn,
SearchResult.BatchID,
SearchResult.Name' + #SQL + '
FROM SearchResult
INNER JOIN Pivoted
ON SearchResult.SearchResultID = Pivoted.SearchResultID;';
EXECUTE SP_EXECUTESQL #SQL;
Example on SQL Fiddle
N.B. I have intentionally used a different way of doing this in dynamic sql just to show there is more than one way to achieve the result of combining the rows.

Select row if column value not same as previous rows

I have a table like below
No. FName Age Tag
1 abc 22 c
2 xyz 60 c
3 pqr 62 i
4 abc 22 i
5 abc 32 i
I want the result to be returned as
No. FName Age Tag
1 abc 22 c
2 xyz 60 c
3 pqr 62 i
5 abc 32 i
Requirement is that if a column Name AND column Age value is same for rows with tag=c and tag=i , than the tag=i row should not be selected . Row no. 1 and Row no. 4 have same values (Name,age)=(abc,22) but row 4 has tag = i.So row no 4 above (abc,22,i) has to be left out. How can I do this ?
WITH records
AS
(
SELECT No, FName, Age, Tag,
ROW_NUMBER() OVER (PARTITION BY FName, Age
ORDER BY Tag ASC) rn
FROM tableName
WHERE TAG IN ('c','i')
)
SELECT No, FName, Age, Tag
FROM records
WHERE rn = 1
SQLFiddle Demo
if you have other special values on TAG,
WITH records
AS
(
SELECT No, FName, Age, Tag,
ROW_NUMBER() OVER (PARTITION BY FName, Age
ORDER BY CASE WHEN TAG = 'c' THEN 0 ELSE 1 END ASC) rn
FROM tableName
WHERE TAG IN ('c','i')
)
SELECT No, FName, Age, Tag
FROM records
WHERE rn = 1
ORDER BY No
SQLFiddle Demo
UPDATE 1
SELECT Fname, Age, MIN(tag) Tag
FROM TableName
WHERE TAG IN ('c','i')
GROUP BY Fname, Age
SQLFiddle Demo
I think you can simply ignore all the rows with tag = 'i' if already exists row with same age, name and tag = 'c' :
select * from TableName t1
where not exists
(select 1
from TableName
where FNAme = t1.FNAme and Age = t1.Age and t1.Tag = 'i' and tag = 'c')