SQL Server Query: Concatenate Multiple Rows during a JOIN - sql

This may have been mentioned here before, but I couldn't find an answer to the exact problem I'm trying to solve.
I am using SSMS 2018 v18.8 with SQL Server 2012 SP4.
My query requires querying multiple tables with joins.
One table (table 2) contains multiple values, and I'd like to return them in the query as a concatenated line.
How should I write my query to return the desired output?

Normally, you want the client application or reporting tool to roll up data like this. However, in Sql Server 2017 and later you can use the string_agg() function (along with GROUP BY) to make this happen.
SELECT t1.System, t1.Location, string_agg(t2.User, ',') As [User]
FROM Table1 t1
INNER JOIN Table2 t2 ON t1.System=t2.System
GROUP BY t1.System, t1.Location
Earlier versions need an ugly FOR XML PATH query.

Very simple answer using US States and Counties, Counties table contains a key (StateID) identifying the State the County belongs to.
SELECT States.name, STRING_AGG(CONVERT(NVARCHAR(max), ISNULL(County,'N/A')), ', ') AS Counties
FROM Counties
join States on Counties.StateID=State.ID
GROUP BY States.name;

Related

How can I write a SQL query to display ID, First Name, Last Name of all players with more than 2000 career hits based on schema

I am new to SQL and DB management. I am working on writing queries based on a schema which you can find below. This is an exercise for me to get familiar reading, writing queries on SQL Server for my job. Could you please help me out defining query based on the schema and simply explain the logic?
Thanks a lot!
SQL Server is my DBMS and here are the question
Display ID, First Name, Last Name, and Hits to display all players with more than 2000 career hits.
This one you can get by typing this query in Microsoft SQL Server
SELECT
MLB_PLAYERS.FIRST_NAME,
MLB_PLAYERS.LAST_NAME,
MLB_PLAYERS.ID,
CAREER_STATS.HITS
FROM
MLB_PLAYERS LEFT JOIN KEY_GAMES_STATS on MLB_PLAYERS.ID=CAREER_STATS.ID
WHERE
CAREER_STATS.HITS>2000
So you have a simple structure to follow:
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
But you decide to get only 3 of them, which is select, from and where. By SELECT you decide which columns you wanna have as an output. Then in FROM you have to choose tables from which you wanna take your variables. But if you decide to use 2 different tables you need to join them. I used left join because I wanted to match hits to existing players. We can match them by similar key, in this case this is their ID. And eventually, you can use where to apply conditions to your queries
I guess you could do it with a join and a group
select p.MLB_PLAYERS.FIRST_NAME,
p.MLB_PLAYERS.LAST_NAME,
p.MLB_PLAYERS.ID,
count(g.KEY_GAMES_STATS.HITS) as hits
from MLB_PLAYERS p
left join KEY_GAMES_STATS on p.ID = g.ID -- not sure how to link there 2 tables
group by p.MLB_PLAYERS.FIRST_NAME,
p.MLB_PLAYERS.LAST_NAME,
p.MLB_PLAYERS.ID
having count(g.KEY_GAMES_STATS.HITS) > 2000

INNER JOIN Syntax Error

I would like to JOIN 2 databases.
1 database is keyword_data (keyword mapping)
1 database is filled with Google rankings and other metrics
Somehow I cannot JOIN these two databases.
Some context:
DATA SET NAME: visibility
TABLE 1
keyword_data
VALUES
keyword
universe
category
search_volume
cpc
DATA SET NAME: visibility
TABLE 2
results
VALUES
Date
Keyword
Website
Position
In order to receive ranking data by date I wrote the following SQL line.
SELECT Date, Position, Website FROM `visibility.results` Keyword INNER
JOIN `visibility.keyword_data` keyword ON `visibility.results` Keyword
= `visibility.keyword_data` keyword GROUP BY Date;
(besides that, 100 other lines with no success ;-) )
I am using Google BigQuery for this with standard SQL (unchecked Legacy SQL).
How can I JOIN those 2 data tables?
How familiar are you with SQL? I think you're using aliases wrong, something like this should work
SELECT r.Date, r.Position, r.Website
FROM `visibility.results` AS r
INNER JOIN `visibility.keyword_data` AS k
ON r.Keyword = k.keyword
GROUP BY DATE
First of all i have never worked with Google big query but there is a couple of things wrong in my opinion with this query.
To start with you join tables by including the name of the table then you provide the key that the tables are joined by. Also if you don't use aggregate functions (MIN/MAX etc.) in your select statement you must include all values in the group by clause as well. In reference I can provide you a solution that would work if you would of used Microsoft SQL Server if that would be of any help because if you reference here the syntax is quite similar.
SELECT results.Date AS DATE,
,results.Position AS POSITION
,results.Website AS WEBSITE
FROM visibility.dbo.keyword_data AS keyword_data
INNER JOIN visibility.dbo.results AS results
ON results.keyword = keyword_data.keyword
GROUP BY results.Date
,results.Position
,results.Website

Access SQL Syntax error: missing operator

I am trying to convert a T-SQL query to MS Access SQL and getting a syntax error that I am struggling to find. My MS Access SQL query looks like this:
INSERT INTO IndvRFM_PreSort (CustNum, IndvID, IndvRScore, IndRecency, IndvFreq, IndvMonVal )
SELECT
IndvMast.CustNum, IndvMast.IndvID, IndvMast.IndvRScore,
IndvMast.IndRecency, IndvMast.IndvFreq, IndvMast.IndvMonVal
FROM
IndvMast
INNER JOIN
OHdrMast ON IndvMast.IndvID = OHdrMast.IndvID
INNER JOIN
MyParameterSettings on 1=1].ProdClass
INNER JOIN
[SalesTerritoryFilter_Check all that apply] ON IndvMast.SalesTerr = [SalesTerritoryFilter_Check all that apply].SalesTerr
WHERE
(((OHdrMast.OrdDate) >= [MyParameterSettings].[RFM_StartDate]))
GROUP BY
IndvMast.CustNum, IndvMast.IndvID, IndvMast.IndvRScore,
IndvMast.IndRecency, IndvMast.IndvFreq, IndvMast.IndvMonVal,
[CustTypeFilter_Check all that apply].IncludeInRFM,
[ProductClassFilter_Check all that apply].IncludeInRFM,
[SourceCodeFilter_Check all that apply].IncludeInRFM,
IndvMast.FlgDontUse
I have reviewed differences between MS Access SQL and T-SQL at http://rogersaccessblog.blogspot.com/2013/05/what-are-differences-between-access-sql.html and a few other locations but with no luck.
All help is appreciated.
update: I have removed many lines trying to find the syntax error and I am still getting the same error when running just (which runs fine using T-SQL):
SELECT
IndvMast.CustNum, IndvMast.IndvID, IndvMast.IndvRScore,
IndvMast.IndRecency, IndvMast.IndvFreq, IndvMast.IndvMonVal
FROM
IndvMast
INNER JOIN
OHdrMast ON IndvMast.IndvID = OHdrMast.IndvID
INNER JOIN
[My Parameter Settings] ON 1 = 1
There are a number of items in your query that should also have failed in any SQL-compliant database:
You have fields from tables in GROUP BY not referenced in FROM or JOIN clauses.
Number of fields in SELECT query do not match number of fields in INSERT INTO clause.
The MyParameterSettings table is not properly joined with valid ON expression.
Strictly MS Access SQL items:
For more than one join, MS Access SQL requires paired parentheses but even this can get tricky if some tables are joined together and their paired result joins to outer where you get nested joins.
Expressions like ON 1=1 must be used in WHERE clause and for cross join tables as MyParameterSettings appears to be, use comma-separated tables.
For above reasons and more, it is advised for beginners to this SQL dialect to use the Query Design builder providing table diagrams and links (if you have the MS Access GUI .exe of course). Then, once all tables connect graphically with at least one field selected, jump into SQL view for any nuanced scripting logic.
Below is an adjustment to SQL statement to demonstrate the parentheses pairings and for best practices, uses table aliases especially with long table names.
INSERT INTO IndvRFM_PreSort (CustNum, IndvID, IndvRScore, IndRecency, IndvFreq, IndvMonVal)
SELECT
i.CustNum, i.IndvID, i.IndvRScore, i.IndRecency, i.IndvFreq, i.IndvMonVal
FROM
[MyParameterSettings] p, (IndvMast i
INNER JOIN
OHdrMast o ON i.IndvID = o.IndvID)
INNER JOIN
[SalesTerritoryFilter_Check all that apply] s ON i.SalesTerr = s.SalesTerr
WHERE
(o.OrdDate >= p.[RFM_StartDate])
GROUP BY
i.CustNum, i.IndvID, i.IndvRScore, i.IndRecency, i.IndvFreq, i.IndvMonVal
And in your smaller SQL subset, the last table does not need an ON 1=1 condition and may be redundant as well in SQL Server. Simply a comma separate table will suffice if you intend for cross join. The same is done in above example:
SELECT
IndvMast.CustNum, IndvMast.IndvID, IndvMast.IndvRScore,
IndvMast.IndRecency, IndvMast.IndvFreq, IndvMast.IndvMonVal
FROM
[My Parameter Settings], IndvMast
INNER JOIN
OHdrMast ON IndvMast.IndvID = OHdrMast.IndvID
I suppose there are some errors in your query, the first (more important).
Why do you use HAVING clause to add these conditions?
HAVING (((IndvMast.IndRecency)>(date()-7200))
AND (([CustTypeFilter_Check all that apply].IncludeInRFM)=1)
AND (([ProductClassFilter_Check all that apply].IncludeInRFM)=1)
AND (([SourceCodeFilter_Check all that apply].IncludeInRFM)=1)
AND ((IndvMast.FlgDontUse) Is Null))
HAVING usually used about conditions on aggregate functions (COUNT, SUM, MAX, MIN, AVG), for scalar value you must put in WHERE clause.
The second: You have 12 parenthesis opened and 11 closed in HAVING clause

DB2 SQL Count across one to many relationship

I have two tables in a one to many relationship within an IBM DB2 database. I can't think of a way to describe what I'm doing in words easily so I'm linking an SQLFiddle.
Here is a working SQLFiddle on what I'm doing;
Click Here
The SQLFiddle works exactly like I need it to. My problem is, I am using an IBM DB2 database and the COUNT function does not seem to work. Does anyone have a way to return what the SQLFiddle does in a IBM DB2 compatible way?
Here is the error I get from i Navigator; Click Here
You are aggregating by the wrong column. I think this is the query you want:
SELECT Table1.quote, COUNT(Table2.quote) as TotalItem
FROM Table1 LEFT JOIN
Table2
ON Table1.quote = Table2.quote
GROUP BY Table1.quote
---------^
You need to aggregate by Table1.quote because Table2.quote might be NULL, because of the LEFT JOIN.
EDIT:
Your particular problem seems to be your having two tables with the same names. Just use column aliases:
SELECT t1.quote, COUNT(t2.quote) as TotalItem
FROM Table1 t1 LEFT JOIN
Table2 t2
ON t1.quote = t2.quote
GROUP BY t1.quote;

problem with IN clause in SQL

We have observed that there seems to be a maximum number of ids/variables which one can pass in the IN clause of SQL as comma separated values. To avoid this we are storing all the ids in a table and doing a SELECT within the IN clause. This however means extra database operations to store and retrieve ids. Is there any other way to use IN without SELECT?
Regards,
Sameer
In SQL Server 2008 you can declare a table variable and pass it to your query from the client or between the procedures.
For a modest number of values I would not have thought an IN (SELECT ..) would be that expensive on any rdbms.
You could INNER JOIN you IDs table or just break down the INs:
WHERE X IN (123,456 ...)
OR X IN (789,987 ...)
...
Agree with Alex
Instead of
Select * From TableA Where ID IN (Select ID from IDTable)
Use
Select * From TableA
INNER JOIN IDTable ON TableA.ID = IDTable.ID
The join will automatically filter the IDs for you.
If you put it in atable why are you still using the in clause, why not just join to the table?