Need help MSSQL query to bring table with two columns into one showing unique value of field 1 and corresponding values in field 2 (in that order)? - sql-server

Picture of current state and desired state
Need help MSSQL query to bring table with two columns into one showing unique value of field 1 and corresponding values in field 2 (in that order)? See picture attached in link above

Your request sounds quite strange, but if you want to do it, one way is to use rollup + grouping_id like this:
select case when grouping_id(field2) = 1 then field1 else field2 end
from yourtable
group by field1, rollup(field2)
order by field1, grouping_id(field2) desc, field2
Usually you'd use this for subtotals, but using it with case you can add additional rows to the data.
This will return:
x
a
b
c
d
y
e
f
g
z
h
i
Edit: How to list table + column names:
select case when grouping_id(c.name) = 1 then t.name else c.name end
from sys.tables t join sys.columns c on t.object_id = c.object_id
group by t.name, rollup(c.name)
order by t.name,c.name

Related

Merge multiple rows into a column while replacing the keys with a 'name' field from the original table

I've got a join table that has 'account_id' and 'group id' in it, both represented by a GUID. I'm trying to merge the columns so we get a single 'account_id' with all of it's 'group_id's merged to a single Colum/row, but display the actual name of the account and group.
Tables
Account
account_id Name
1 Henry
2 Smith
Group
Group_id Group_nameName
3 User
4 Admin
Account_Group_Join_Table
account_id group_id
1 3
1 4
2 3
Desired Result:
Name Groups
Henry Dev,User
Smith User, Admin
Code so far to return 'account_id' with 'group_id' grouped to single row/column
select account_id,
stuff((SELECT distinct ', ' + group_id
FROM account_group_join t2
where t2.account_id = t1.account_id
FOR XML PATH('')),1,1,'') [Groups]
from account_group_join t1
group by account_id
You just need to join to your group table in the subquery so you can get the name rather than the ID. You also may as well just select from Account in the outer query and avoid an additional join to account to get the name:
SELECT a.account_id,
a.Name,
STUFF((SELECT DISTINCT ', ' + g.group_nameName
FROM account_group_join AS ag
INNER JOIN [Group] AS g
ON g.group_id = ag.group_id
WHERE ag.account_id = a.account_id
FOR XML PATH('')),1,1,'') AS [Groups]
from Account AS a;
n.b. I've changed your aliases from t1 and t2 to something that kind of represents the table I am aliasing, you'll find this much easier especially when working with larger queries. More reading here: Bad Habits to Kick : Using table aliases like (a, b, c) or (t1, t2, t3)

Returned by a subquery

GOAL
I have a table A with column NAME, I would like that whenever column NAME of table A, is equal to column NAME of table B, is selected in column CODE_CLIENT of table B
QUERY
SELECT
CASE WHEN name = (select name from tb_get_names)
THEN (select code_client from tb_get_names)
ELSE 'null'
END AS Result FROM tb_get_clients
OUTPUT
ERROR: more than one row returned by a subquery used as an expression
Each of the 2 subqueries you use, return all the names or all the code_clients of the table tb_get_names. This is why you get the error.
You need a LEFT JOIN:
SELECT
c.name,
n.code_client AS Result
FROM tb_get_clients AS c LEFT JOIN tb_get_names AS n
ON n.name = c.name

How to divide to multiple column sql?

Based on the sql result above i want to divide the result like the image below
I tried using case it return duplicate data.
Anyone have done this or have any idea how to do this?
Can you try this one?
SELECT t1.*,t2.* from yourtable WHERE t1.hatch_num_1 != t2.hatch_num_1
JOIN yourtable t2 ON t1.delay_code_1=t2.delay_code_1
Afterwards you can mention exactly what columns you wan't from both t1 and t2 and mention with 'as' how do you wan't them to be named in your select statement, so instead of having 2 hatch_num_1 you wil have one with _1 and one with _3
;With
a As (SELECT * FROM yourtable X Where X.hatch= 'H1' ),
b AS (SELECT * FROM yourtable Y Where Y.hatch= 'H3')
SELECT A.* ,B.* FROM A , B WHERE A.[delay] = B.[delay]
If you have limited hatches and same time that are repeating then you can do it like this or show me some more records or details then i'll came to know...

Selecting Max with Lots of Other Items

Sorry for the poor title. I wasn't sure how to describe my problem. I've written a query that returns about 23,000 records. A lot of those records have similar information and I want to only select the records with the maximum of the field dbo.tblMsgsOnAir_Type8.fldBuddyLinkSigStrength. I've tried grouping by all of the other columns being selected, but it doesn't appear to work correctly. I don't fully understand SQL, especially the max and group functions. I can do simple max functions when I only want or need to select one thing. I don't understand how it works when I want to select a bunch of other data. Below is the query.
SELECT
dbo.tblmeterinfo.fldMeterSerialNumber AS "MOP_FNP_Meter",
dbo.tblMsgsOnAir_Type8.fldRBuddyId AS "MOP_FNP_FNID",
dbo.TBLMETERMAINT.fldmeterid AS "Meter_ID_Helped",
dbo.tblMsgsOnAir_Type8.fldCBuddyId AS "FNID_Helped",
dbo.fn_dt(dbo.tblMsgsOnAir_Type8.fldRBuddyToi) AS "TOI",
dbo.tblMsgsOnAir_Type8.fldBuddyLinkSigStrength AS "Sig_Str",
dbo.TBLSAWN_CIS_INFO.SML AS "Buddy_SML",
dbo.TBLMETERLIST.fldaddress AS "Buddy_Address",
dbo.TBLSAWNGISCOORD.X_COORD AS "X_Coord",
dbo.TBLSAWNGISCOORD.Y_COORD AS "Y_Coord"
FROM dbo.tblMsgsOnAir_Type8
LEFT OUTER JOIN dbo.TBLMETERLIST
ON (dbo.TBLMETERLIST.FLDREPID = dbo.tblMsgsOnAir_Type8.fldCBuddyId)
LEFT OUTER JOIN dbo.TBLMETERMAINT
ON (dbo.TBLMETERMAINT.FLDREPID = dbo.tblMsgsOnAir_Type8.fldCBuddyID)
LEFT OUTER JOIN dbo.TBLSAWN_CIS_INFO
ON (dbo.TBLSAWN_CIS_INFO.FLDREPID = dbo.tblMsgsOnAir_Type8.fldCBuddyId)
LEFT OUTER JOIN dbo.TBLSAWNGISCOORD
ON (dbo.TBLSAWNGISCOORD.SRV_MAP_LOC = dbo.TBLSAWN_CIS_INFO.SML)
LEFT OUTER JOIN dbo.tblmeterinfo
ON (dbo.tblmeterinfo.fldRepId = dbo.tblMsgsOnAir_Type8.fldRBuddyId)
WHERE dbo.tblMsgsOnAir_Type8.fldRBuddyId IN (SELECT
dbo.tblSAWN_FNPmap.Repid
FROM dbo.tblSAWN_FNPmap)
AND dbo.TBLMETERMAINT.fldmeterid IS NOT NULL
The query below is simple and does what I want, but doesn't get all of the other field. This query only returns 617 records. I would like the above query to return 617 records, but include all of the other information I've selected.
SELECT
dbo.TBLMETERMAINT.fldmeterid AS "Meter_ID_Helped",
MAX(dbo.tblMsgsOnAir_Type8.fldBuddyLinkSigStrength) AS "Max_Sig"
FROM dbo.tblMsgsOnAir_Type8
LEFT OUTER JOIN dbo.TBLMETERMAINT
ON (dbo.TBLMETERMAINT.FLDREPID = dbo.tblMsgsOnAir_Type8.fldCBuddyID)
WHERE dbo.tblMsgsOnAir_Type8.fldRBuddyId IN (SELECT
dbo.tblSAWN_FNPmap.Repid
FROM dbo.tblSAWN_FNPmap)
AND dbo.TBLMETERMAINT.fldmeterid IS NOT NULL
GROUP BY dbo.TBLMETERMAINT.fldmeterid
Probably row_number() to the rescue. You can use it to find the best records in a set, with a grouping by some subset or other. Something like
select *
from ....
where row_number over (partition by id order by fldBuddyLinkSigStrength) = 1
So SQL Server assigns a row number within the groups. Each record will be sub-grouped by id, in this case, and given 1 if it's the best strength, 2 if it's next, etc.
If you are getting duplicates have you tried using SELECT DISTINCT?
Basically how Max works is that it will select the highest value in the group.
So if you have a table:
ID | VALUE
1 | 10
1 | 7
1 | 9
2 | 6
2 | 8
And do
SELECT ID, MAX(VALUE)
FROM TABLE
GROUP BY ID
You'll get the max value per ID
ID | VALUE
1 | 10
2 | 8
If you want to get the Max while not grouping the result then you can do the group in a subselect
SELECT ID, VALUE, MAX_VALUE etc etc
FROM TABLE
JOIN ( SELECT ID, MAX(VALUE) AS MAX_VALUE FROM TABLE GROUP BY ID) as MAX ON MAX.ID = TABLE.ID
Without knowing your table structures in more detail I can't be sure this is the best way, but here's something that should work. Use the 2nd query as the left side of a left join, to pick up the extra columns:
select a.*
from (<your 2nd query>) a
left join dbo.TBLMETERLIST
on (a.FLDREPID = dbo.tblMsgsOnAir_Type8.fldCBuddyId)
left join <next table> ...
and so on. You'll also have to left join on dbo.tblMsgsOnAir_Type8 in order to pick up the columns in that table, so that's one additional left join beyond what your first query does. By the way, it's a good idea to post code here laid out so it's readable; it makes it a lot easier for others to understand.

SQL Join one-to-many tables, selecting only most recent entries

This is my first post - so I apologise if it's in the wrong seciton!
I'm joining two tables with a one-to-many relationship using their respective ID numbers: but I only want to return the most recent record for the joined table and I'm not entirely sure where to even start!
My original code for returning everything is shown below:
SELECT table_DATES.[date-ID], *
FROM table_CORE LEFT JOIN table_DATES ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
ORDER BY [table_CORE].[core-ID], [table_DATES].[iteration];
This returns a group of records: showing every matching ID between table_CORE and table_DATES:
table_CORE date-ID iteration
1 1 1
1 1 2
1 1 3
2 2 1
2 2 2
3 3 1
4 4 1
But I need to return only the date with the maximum value in the "iteration" field as shown below
table_CORE date-ID iteration Additional data
1 1 3 MoreInfo
2 2 2 MoreInfo
3 3 1 MoreInfo
4 4 1 MoreInfo
I really don't even know where to start - obviously it's going to be a JOIN query of some sort - but I'm not sure how to get the subquery to return only the highest iteration for each item in table 2's ID field?
Hope that makes sense - I'll reword if it comes to it!
--edit--
I'm wondering how to integrate that when I'm needing all the fields from table 1 (table_CORE in this case) and all the fields from table2 (table_DATES) joined as well?
Both tables have additional fields that will need to be merged.
I'm pretty sure I can just add the fields into the "SELECT" and "GROUP BY" clauses, but there are around 40 fields altogether (and typing all of them will be tedious!)
Try using the MAX aggregate function like this with a GROUP BY clause.
SELECT
[ID1],
[ID2],
MAX([iteration])
FROM
table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE
table_CORE.[core-ID] Like '*' --LIKE '%something%' ??
GROUP BY
[ID1],
[ID2]
Your example field names don't match your sample query so I'm guessing a little bit.
Just to make sure that I have everything you’re asking for right, I am going to restate some of your question and then answer it.
Your source tables look like this:
table_core:
table_dates:
And your outputs are like this:
Current:
Desired:
In order to make that happen all you need to do is use a subquery (or a CTE) as a “cross-reference” table. (I used temp tables to recreate your data example and _ in place of the - in your column names).
--Loading the example data
create table #table_core
(
core_id int not null
)
create table #table_dates
(
date_id int not null
, iteration int not null
, additional_data varchar(25) null
)
insert into #table_core values (1), (2), (3), (4)
insert into #table_dates values (1,1, 'More Info 1'),(1,2, 'More Info 2'),(1,3, 'More Info 3'),(2,1, 'More Info 4'),(2,2, 'More Info 5'),(3,1, 'More Info 6'),(4,1, 'More Info 7')
--select query needed for desired output (using a CTE)
; with iter_max as
(
select td.date_id
, max(td.iteration) as iteration_max
from #table_dates as td
group by td.date_id
)
select tc.*
, td.*
from #table_core as tc
left join iter_max as im on tc.core_id = im.date_id
inner join #table_dates as td on im.date_id = td.date_id
and im.iteration_max = td.iteration
select *
from
(
SELECT table_DATES.[date-ID], *
, row_number() over (partition by table_CORE date-ID order by iteration desc) as rn
FROM table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
) tt
where tt.rn = 1
ORDER BY [core-ID]

Resources