nontrivial query - sql-server

I need to write a query.
have 3 tables, one main and two associated
for example :
main_table
id name
-- -------------
1 example
2 example2
join_table1
id main_table_id
-- -------------
1 1
join_table2
id main_table_id
-- -------------
1 2
if main_table_id contained in join_table1
I need to sort by join_table1.id, else if main_table_id contained in join_table2,
i need to sort by join_table2.id
any ideas how to make such query
main_table_id can be either in table join_table1 or join_table2
database - SQL Server

You should combine coalesce and left joins. Query will look like:
select ...
from main_table
left outer join join_table1 j1 on ...
left outer join join_table2 j2 on ...
order by coalesce( j1.id, j2.id )

Related

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]

how to do a FOR EACH loop in T-Sql using join?

I have a table PRODUCT that is basically set up so there is an PRODUCTID, PRODUCTNAME... it looks sort of like this
PRODUCTID PRODUCTNAME
100 PNAME1
101 PNAME2
102 PNAME3
Now I have to insert a record into new table PRODUCTMAPPING for each row in the PRODUCT.
so my new table PRODUCTMAPPING should look like this
PRODUCTMAPPINGID PRODUCTID
1 100
1 101
1 102
2 100
2 101
2 102
3 100
and so on ....
I tried doing while but I need it using Join.
Can we acheive this using joins ?
Thanks in advance.
One way;
select
row_number() over(partition by a.PRODUCTID order by a.PRODUCTID) PRODUCTMAPPINGID,
a.PRODUCTID
from PRODUCT a, PRODUCT b
Using LOOP
The following example specifies that the JOIN operation in the query is performed by a LOOP join.
Select sp.Name,spqh.quota
FROM Sales.SalesPersonQuotaHistory AS spqh
INNER LOOP JOIN Sales.SalesPerson AS sp
ON spqh.SalesPersonID = sp.SalesPersonID
WHERE sp.SalesYTD > 2500000.00;
GO
Refer this MSDN link
INSERT
INTO dbo.PRODUCTMAPPING
(
PRODUCTMAPPINGID
,PRODUCTID
)
SELECT pmv.PRODUCTMAPPINGID
,p.PRODUCTID
FROM dbo.Product p
CROSS JOIN
(
SELECT pm.ProductMappingID
FROM dbo.ProductMappingValues pmv -- WHERE DO THESE COME FROM?
) pmv

Get union of two table and taking data with a condition

I have two tables
table-a
id name
100 asd
101 ass
102 gdd
103 hgf
104 cvd
105 erf
table-b
id filter
100 red
101 blue
100 green
100 yellow
102 black
102 red
103 dark
Table-a is the master table and that have all the id's.but Table two is the one which has 'filter' data.
from these two table I want to find out all those 'id's which does not have minimum 2 filters.
note that table-b does not have all the itemnumbers in table-a, and i want all that itemnumber irrespective of if that is in table-a or table-b.I have tried inner joining these two tables and getting data out but nothing worked.
Select A.ID, A.Name, count(*)
from tableA A
LEFT JOIN tableB B on A.ID = B.ID
Group By A.ID, A.name
having count(*) <= 1
LEFT JOIN gives all records from A and only those in B which match.
The group by ID and name let us count the number of filters found in
each
The having says give me any items with a count less than or
equal to 1. (or less than the minimum 2)
Thus results would be.
101 ass 1
103 hgf 1
104 cvd 0
105 erf 0
select
*
from
table-a a
left join (
select id, count(id) as c from table-b group by id
) v on a.id = v.id
where isnull(v.id, 0) < 2
I think this would work in SQL Server (tested in SQLite and usually the two are fairly compatible when it comes to inline view syntax). But syntax issues aside, inline views can make working with sets easier to visualize.
select TA.id, name
from TA
inner join
(
select id from TA
where not exists (select id from TB where TA.id = TB.id)
UNION
select id from TB
group by id having count(filter) < 2
) as FOO
on TA.id = FOO.id
The default behavior of UNION is to remove duplicates.
The first UNIONed set consists of the ids from table A that have no filter (no counterpart in the filters table B).
The second UNIONed set consists of the ids from the filters table, table B, that have only 1 filter.
We inner join those unioned sets back to Table A to get the entity Name.

SQL View - Combine multiple rows into 1 row

I am trying to make a new view using in MSSql 2008 from three tables:
Table 1 has customer id and transaction id
Table 1
CustomerID TransactionID
1 1
1 2
Table 2 has Purchases Transaction and Products ID
TransactionID ProductID
1 x
2 y
Table 3 has Products Names
ProductID Name
1 x
2 y
I view I would like to make should show
CustomerID Product Name
1 x, y
When I use the following query:
SELECT table1. CustomerID, table3.Name
FROM table1 LEFT OUTER JOIN
Table2 ON table2. TransactionID = table1.VisitId LEFT OUTER JOIN
Table3 ON table2. ProductID = Table3. ProductID
GROUP BY table1. CustomerID, table3.Name
I get
CustomerID Product Name
1 x
1 y
Thanks in Advance
One way to do this is to use a user defined function, something like:
SELECT table1.CustomerID, dbo.BuildStringOfCustomerProductNames(table1.CustomerID)
FROM table1
And create a user defined function like: dbo.BuildStringOfCustomerProductNames
that takes a customerid as input.
Inside there, you can run a query to loop through the table 2 and table 3 joined records to make a string, and return that.
Off hand I can't think of any other simple way to do it.

Resources