grouping items in sql query - sql

I have a table with columns like (in sql server 2000)
MailCode Mode Name Group
-------- ----- --------- -------
1 1 abc 0
1 1 def 0
1 1 qwe 1
2 2 aaw 0
2 2 aad 0
I want to group the Name field based on the rest of the fileds so that the result looks like this (there should be only one unique mailCode, Mode and group combination)
MailCode Mode Names Group
--------- ------ ------------ -------
1 1 abc, def 0
1 1 qwe 1
2 2 aaw, aad 0
How can I create the sql query for this?

I had a similar problem where I had to concatenate a field in the select, my solution at the time was to create a procedure that returned the result and called it like this
select x as field1, y as field2, dbo.procedure as field3

SQL Server 2000 solution
Luckily, COALESCE is supported in 2000, so you can use the COALESCE trick to create a comma delimited list of values, demonstrated in this link. Because of the variable usage, you'll need to create a function/procedure and call it within the main query. Basically, just replace the STUFF() in the query below with the function call.
SQL Server 2005+ solution:
SELECT x.mailcode,
x.mode,
STUFF((SELECT y.name
FROM TABLE y
WHERE y.mailcode = x.mailcode
AND y.mode = x.mode
AND y.gropu = x.group
GROUP BY y.mailcode, y.mode, y.group
FOR XML PATH(', ')), 1, 1, '') AS name,
x.group
FROM TABLE x
GROUP BY x.mailcode, x.mode, x.group

I can't think of a simple query that will get the result you're looking for, but some logic along these lines should get you where you want:
1) Loop through distinct MailCode, Mode, Group Rows
A) select all names in group
A.1) Loop through names
A.2) Concatenate them together into temp variable
B) insert all data (MailCode, Mode, Group, temp variable) into temp table
Fair waring, looping in SQL tends to have a huge performance hit when it comes to large datasets. I unfortunately don't know a better way to do it.

Related

Alternative for GROUP BY and STUFF in SQL

I am writing some SQL queries in AWS Athena. I have 3 tables search, retrieval and intent. In search table I have 2 columns id and term i.e.
id term
1 abc
1 bcd
2 def
1 ghd
What I want is to write a query to get:
id term
1 abc, bcd, ghd
2 def
I know this can be done using STUFF and FOR XML PATH but, in Athena all the features of SQL are yet not supported. Is there any other way to achieve this. My current query is:
select search.id , STUFF(
(select ',' + search.term
from search
FOR XML PATH('')),1,1,'')
FROM search
group by search.id
Also, I have one more question. I have retrieval table that consist of 3 columns i.e.:
id time term
1 0 abc
1 20 bcd
1 100 gfh
2 40 hfg
2 60 lkf
What I want is:
id time term
1 100 gfh
2 60 lkf
I want to write a query to get the id and term on the basis of max value of time. Here is my current query:
select retrieval.id, max(retrieval.time), retrieval.term
from search
group by retrieval.id, retrieval.term
order by max(retrieval.time)
I am getting duplicate id's along with the term. I think it is because, I am doing group by on id and term both. But, I am not sure how can I achieve it without using group by.
The XML method is brokenness in SQL Server. No reason to attempt it in any other database.
One method uses arrays:
select s.id, array_agg(s.term)
from search s
group by s.id;
Because the database supports arrays, you should learn to use them. You can convert the array to a string:
select s.id, array_join(array_agg(s.term), ',') as terms
from search s
group by s.id;
Group by is a group operation: think that you are clubbing the results and have to find min, max, count etc.
I am answering only one question. Use it to find the answer to question 1
For question 2:
select
from (select id, max(time) as time
from search
group by id, term
order by max(time)
) search_1, search as search_2
where search_1.id = search_2.id
and search_1.time = search_2.time

How to show blank instead of column value for all duplicated columns of a SQL query?

There is a similar question which answer this for a known number of columns and only a single selection column. But the problem here is that
I have no knowledge of columns (count, type) of a specified SQL query and also I want to blank for all columns not a single column.
For example lets say I have following query.
Select * from View1
Result :
Column(1) Column(2) Column(..) Column(N)
1 A Sales 1500
2 C Sales 2500
3 C Sales 2500
4 A Development 2500
Expected result :
Column(1) Column(2) Column(..) Column(N)
1 A Sales 1500
2 C 2500
3
4 A Development
Pseudo SQL Query :
EXEC proc_blank_query_result 'Select * from View1'
If you're in SQL Server 2012 or newer, you can do this with lag, something like this:
select
nullif(column1, lag(column1) over (order by yourorderbyclause)) as column1,
nullif(column2, lag(column2) over (order by yourorderbyclause)) as column2,
...
from
View1
To make it dynamic, well then you have to parse a lot of metadata from the query. Using sp_describe_first_result_set might be a good idea, or use select into a temp. table and parse the columns of it.

Need to Transform a Rows of Data into a single Row

I have a set of Data in MS Access
Number Owner
1 Heelo
1 Hi
1 There
2 What
2 Up
This needs to be transferrid into
Number Owner1 Owner2 Owner3 Owner4
1 Heelo Hi There -
2 What Up - -
Any idea on how to go on with this?
The crux in this case is we don't have a third column from where we can pivot the data.
You could add a third column with a sequence of numbers:
SELECT Number, (select count(*)
from YourTable as s
where s.number = t.number) as sequence, owner
from YourTable as t
then apply this solution to the results: SQL to transpose row pairs to columns in MS ACCESS database

To select a unique value from a column having multiple values MS Access

Table Structure is like this
Table Name:Employee
**Employee_Id APPRS_TY_CD**
540589 2
540589 UNK
1952938 2
1952938 UNK
2488178 1
2488178 UNK
3818934 1
3818934 UNK
5402944 1
If a Employee ID has APPRS_TY_CD as (UNK AND a value) then APPRS_TY_CD should be a value and not UNK. If APPRS_TY_CD is not UNK for an Employee ID then that value should be populated as it is.
My final output should look like this.
**Employee_Id APPRS_TY_CD**
540589 2
1952938 2
2488178 1
3818934 1
5402944 1
I'm using MS Access.
This should be fairly simple as numbers are considered "lower" than strings you can use an aggregate function, I've created an SQL Fiddle here (note this is Sql Server but the code should be the same as it's not using proprietary features). Given your data you could use the MIN function from SQL to get the APPRS_TY_CD for each user. Here is my suggested code:
SELECT
Employee_Id
, MIN(APPRS_TY_CD) APPRS_TY_CD
FROM
Employee
GROUP BY
Employee_Id
The results returned are (you should be able toe execute the fiddle yourself to prove this):
EMPLOYEE_ID APPRS_TY_CD
540589 2
1952938 2
2488178 1
3818934 1
5402944 1

SQL query for aggregate on multiple rows

I have data in a table like following
Name indicator
A 1
A 2
A 3
B 1
B 2
C 3
I want to get count of Names, for which both indicator 1,2 exists. In the preeceding example, this number is 2 (A & B both have indicator as 1, and 2).
The data I am dealing with is moderately large, and i need to get the similar information of some other permutations of (pre defined ) indicators (which i can change, once i get base query).
Try this:
SELECT Name
FROM Tablename
WHERE indicator IN(1, 2)
GROUP BY Name
HAVING COUNT(DISTINCT indicator) = 2;
See it in action here:
SQL Fiddle Demo