How to use XML Path to generate a grid - sql

I need to output results of a query to a grid, rather a long list of values.
What I have right now is
(SELECT COLUMN1+' '+COLUMN2
FROM TABLE
FOR XML PATH) AS MyGrid
Results I have are displayed as
Bob s12345 Chuck s54321
I would like to have them displayed as
Bob s12345
Chuck s54321
Any help, please?
Added table records
CustID | CustName | StoreNumber | City
------+----------+--------------+-----------
1 | Bob | s12345 | Somewhere
2 | Chuck | s54321 | Town
3 | Paul | s19285 | BillaBong
4 | David | s65478 | North
5 | Arnold | s47381 | South
The MyGrid ALIAS is passed to Outlook as merge field.

you can use cross apply with values
select value1,value2 from table
cross apply
(values (value3 ,value4))b(v1,v2)

Related

SQL - specific requirement to compare tables

I'm trying to merge 2 queries into 1 (cuts the number of daily queries in half): I have 2 tables, I want to do a query against 1 table, then the same query against the other table that has the same list just less entries.
Basically its a list of (let's call it for obfuscation) people and hobby. One table is ALL people & hobby, the other shorter list is people & hobby that I've met. Table 2 would all be found in table 1. Table 1 includes entries (people I have yet to meet) not found in table 2
The tables are synced up from elsewhere, what I'm looking to do is print a list of ALL people in the first column then print the hobby ONLY of people that are on both lists. That way I can see the lists merged, and track the rate at which the gap between both lists is closing. I have tried a number of SQL combinations but they either filter out the first table and match only items that are true for both (i.e. just giving me table 2) or just adding table 2 to table 1.
Example of what I'm trying to do below:
+---------+----------+--+----------+---------+--+---------+----------+
| table1 | | | table2 | | | query | |
+---------+----------+--+----------+---------+--+---------+----------+
| name | hobby | | activity | person | | name | hobby |
| bob | fishing | | fishing | bob | | bob | fishing |
| bill | vidgames | | hiking | sarah | | bill | |
| sarah | hiking | | planking | sabrina | | sarah | hiking |
| mike | cooking | | | | | mike | |
| sabrina | planking | | | | | sabrina | planking |
+---------+----------+--+----------+---------+--+---------+----------+
Normally I'd just take the few days to learn SQL a bit better however I'm stretched pretty thin at work as it is!
I should mention the table 2 is flipped and the headings are all unique (don't think this matters)!
I think you just want a left join:
select t1.name, t2.activity as hobby
from table1 t1 left join
table2 t2
on t1.name = t2.person;

Simple SQL Query to bring back null if no match found

EDIT
I've edited this question to make it a little more concise, if you see my edit history you will see my effort and 'what I've tried' but it was adding a lot of unnecessary noise and causing confusion so here is a summary of input and output:
People:
ID | FullName
--------------------
1 | Jimmy
2 | John
3 | Becky
PeopleJobRequirements:
ID | PersonId | Title
--------------------
1 | 1 | Some Requirement
2 | 1 | Another Requirement
3 | 2 | Some Requirement
4 | 3 | Another Requirement
Output:
FullName | RequirementTitle
---------------------------
Jimmy | Some Requirement
Jimmy | Another Requirement
John | Some Requirement
John | null
Becky | null
Becky | Another Requirement
Each person has 2 records, because that's how many distinct requirements there are in the table (distinct based on 'Title').
Assume there is no third table - the 'PeopleJobRequirements' is unique to each person (one person to many requirements), but there will be duplicate Titles in there (some people have the same job requirements).
Sincere apologies for any confusion caused by the recent updates.
CROSS JOIN to get equal record for each person and LEFT JOIN for matching records.
Following query should work in your scenario
select p.Id, p.FullName,r.Title
FROM People p
cross join (select distinct title from PeopleJobRequirements ) pj
left join PeopleJobRequirements r on p.id=r.personid and pj.Title=r.Title
order by fullname
Online Demo
Output
+----+----------+---------------------+
| Id | FullName | Title |
+----+----------+---------------------+
| 3 | Becky | Another Requirement |
+----+----------+---------------------+
| 3 | Becky | NULL |
+----+----------+---------------------+
| 1 | Jimmy | Some Requirement |
+----+----------+---------------------+
| 1 | Jimmy | Another Requirement |
+----+----------+---------------------+
| 2 | John | NULL |
+----+----------+---------------------+
| 2 | John | Some Requirement |
+----+----------+---------------------+
use left join, no need any subquery
select p.*,jr.*,jrr.*
from People p left join
PeopleJobRequirements jr on p.Id=jrPersonId
left join JobRoleRequirements jrr p.id=jrr.PersonId
according the explanation, People and PeopleJobRequirements tables have many to many relationship (n to n).
so first of all you'll need another table to relate these to table.
first do this and then a full join will make it right.

How to get every first result of select query in loop iterating over array of strings?

I have a table (e.g. Users) in PostgreSQL database. Its size is relatively large (ca. 4 GB of data) and I would like to get a table/result consisting of single rows fulfilling the select query. This query shall be executed for each element in an array of strings (couple dozens of elements).
Example single select for one element:
SELECT * FROM "Users" WHERE "Surname" LIKE 'Smith%' LIMIT 1
Value between ' and %' should be an element of input array.
EDIT: It doesn't matter for me whether I get record no. 1 or 2 for LIKE 'Smith%'
How can I achieve this?
I tried to append query results to some array variable within FOREACH loop but with no success.
Example source table:
| Id | Name | Surname |
|---- |-------- |---------- |
| 1 | John | Smiths |
| 2 | Adam | Smith |
| 3 | George | Kowalsky |
| 4 | George | Kowalsky |
| 5 | Susan | Connor |
| 6 | Clare | Connory |
| 7 | Susan | Connor |
And for ['Smith', 'Connor'] the output is:
| Id | Name | Surname |
|----|-------|---------|
| 1 | John | Smiths |
| 5 | Susan | Connor |
In Postgres you can use the ANY operator to compare a single value to all values of an array. This also works with together with the LIKE operator.
SELECT *
FROM "Users"
WHERE "Surname" like ANY (array['Smith%', 'Connor%'])
Note that LIKE is case sensitive, if you don't want that, you can use ILIKE
This will show you the logic. Syntax is up to you.
where 1 = 2
start of loop
or surname like 'Array Element goes here%'
end of loop

Parsing an column containing integers

I am writing a query that pulls 50 fields from 12 sub-queries in the FROM statement. Each sub query is left-joined on two fields the Item SKU and Brand ID. However there is one table where the Brand ID is concatenated in a comma delimited column.
My problem is that I am having trouble parsing this column so that I can use it as a foreign key to join to the other sub-queries. I tried setting the column = to a variable and then using the String_Split function, but was getting the error 'No column selected for column 1' in the query. If anyone has any suggestions of how to parse this data into a NEW row so that SKU that has multiple brands associated to it each has a row showing that SKU and Brand. I have added a screen shot of the data that needs to be parsed. Thanks!
Isn't this example on the MSSQL docs exactly what you're trying to do?
+-----------+--------------------+----------------------------+
| ProductId | Name | Tags |
+-----------+--------------------+----------------------------+
| 1 | Full-Finger Gloves | clothing,road,touring,bike |
| 2 | LL Headset | bike |
| 3 | HL Mountain Frame | bike,mountain |
+-----------+--------------------+----------------------------+
gets transformed into (note the change in the column name!)
+-----------+--------------------+----------+
| ProductId | Name | value |
+-----------+--------------------+----------+
| 1 | Full-Finger Gloves | clothing |
| 1 | Full-Finger Gloves | road |
| 1 | Full-Finger Gloves | touring |
| 1 | Full-Finger Gloves | bike |
| 2 | LL Headset | bike |
| 3 | HL Mountain Frame | bike |
| 3 | HL Mountain Frame | mountain |
+-----------+--------------------+----------+
using
SELECT ProductId, Name, value
FROM Product
CROSS APPLY STRING_SPLIT(Tags, ',');
Since you didn't share any code, it's impossible for me to be more specific... but this example really seems to me should be the piece you're missing.

JOIN, aggregate and convert in postgres between two tables

Here are the two tables i have: [all columns in both tables are of type "text"], Table name and the column names are in bold fonts.
Names
--------------------------------
Name | DoB | Team |
--------------------------------
Harry | 3/12/85 | England
Kevin | 8/07/86 | England
James | 5/05/89 | England
Scores
------------------------
ScoreName | Score
------------------------
James-1 | 120
Harry-1 | 30
Harry-2 | 40
James-2 | 56
End result i need is a table that has the following
NameScores
---------------------------------------------
Name | DoB | Team | ScoreData
---------------------------------------------
Harry | 3/12/85 | England | "{"ScoreName":"Harry-1", "Score":"30"}, {"ScoreName":"Harry-2", "Score":"40"}"
Kevin | 8/07/86 | England | null
James | 5/05/89 | England | "{"ScoreName":"James-1", "Score":"120"}, {"ScoreName":"James-2", "Score":"56"}"
I need to do this using a single SQL command which i will use to create a materialized view.
I have gotten as far as realising that it will involve a combination of string_agg, JOIN and JSON, but haven't been able to crack it fully. Please help :)
I don't think the join is tricky. The complication is building the JSON object:
select n.name, n.dob, n.team,
json_agg(json_build_object('ScoreName', s.name,
'Score', s.score)) as ScoreData
from names n left join
scores s
ons.name like concat(s.name, '-', '%')
group by n.name, n.dob, n.team;
Note: json_build_object() was introduced in Postgres 9.4.
EDIT:
I think you can add a case statement to get the simple NULL:
(case when s.name is null then NULL
else json_agg(json_build_object('ScoreName', s.name,
'Score', s.score))
end) as ScoreData
Use json_agg() with row_to_json() to aggregate scores data into a json value:
select n.*, json_agg(row_to_json(s)) "ScoreData"
from "Names" n
left join "Scores" s
on n."Name" = regexp_replace(s."ScoreName", '(.*)-.*', '\1')
group by 1, 2, 3;
Name | DoB | Team | ScoreData
-------+---------+---------+---------------------------------------------------------------------------
Harry | 3/12/85 | England | [{"ScoreName":"Harry-1","Score":30}, {"ScoreName":"Harry-2","Score":40}]
James | 5/05/89 | England | [{"ScoreName":"James-1","Score":120}, {"ScoreName":"James-2","Score":56}]
Kevin | 8/07/86 | England | [null]
(3 rows)