Display multiple rows in a single row - sql

I have been trying to achieve this:
Instead I am getting similar but NOT the result I'm hoping for:
In thos result that I got from my query, I have rows repeating the SAME thing. For example, if you look at the first 4 results that I highlighted, I want the 1st row to appear and the next 3 to disappear, just like in the first image attached, NO repetition.
I have tried my ways but have got nothing. As in the first image attached, that is the kind of result I am looking for. Kind of nested rows in the last column. Below is what I have tried. I am also attaching a link to my .sql file for ease if anyone can help me with this problem (link). I am using MS SQL.
SELECT cj.completed_job_id AS 'Job Card No.',
c.cus_name AS 'Customer',
c.cus_address AS 'Address',
jt.job_type AS 'Job Type',
cj.no_of_days AS 'No. of Days',
CONCAT(jm.mat_quantity, ' ', jm.mat_type) AS 'Materials Used'
FROM completed_jobs cj
JOIN customers c
ON cj.customer_id = c.customer_id
JOIN job_types jt
ON cj.job_type = jt.job_type
JOIN job_materials jm
ON cj.completed_job_id = jm.completed_job_id;

You can select all of columns without "material used" and make subquery that contains only "material used" for that row.
In that subquery you can convert result to xml to put results into one cell and in next step replace xml tags.
Not very elegant but working - part of SQL below:
SELECT cj.completed_job_id AS 'Job Card No.',
c.cus_name AS 'Customer',
c.cus_address AS 'Address',
jt.job_type AS 'Job Type',
cj.no_of_days AS 'No. of Days',
(SELECT CONCAT(jm.mat_quantity, ' ', jm.mat_type) as material FROM job_materials jm WHERE cj.completed_job_id = jm.completed_job_id FOR XML AUTO) AS 'Materials Used'
FROM completed_jobs cj
JOIN customers c
ON cj.customer_id = c.customer_id
JOIN job_types jt
ON cj.job_type = jt.job_type

Related

SQL Server query stuck when adding order by clause

I'm working on writing some queries for a very large (and messy) database on behalf of a client. So far, I've just been grabbing the columns I need and making sure that they contain the data I'm looking for. There have been no issues up until I add anything to my "order by" clause. When I add an order by clause to my query, the SQL Server remains stuck on "executing query." Example of code below:
SELECT TOP 100
PEATR.[EffectiveDate] AS 'Effective Date',
CustomerRoot.[CustomerName] AS 'Name',
CustomerAddressRoot.[Street1] AS 'Address 1',
CustomerAddressRoot.[Street2] AS 'Address 2',
CustomerAddressRoot.[City],
CustomerAddressRoot.[State],
CustomerAddressRoot.[Zip],
CustomerAddressRoot.[Country],
CustomerAddressRoot.[AddressDesc] AS 'Description'
FROM PrEmployeeAccrueTierRoot AS PEATR, CustomerRoot, CustomerAddressRoot
ORDER BY CustomerRoot.[CustomerName]
I have also tried creating an inner join on CustomerRoot and CustomerAddressRoot, as the query is returning repeat data, especially in the "Address 1" column. When I ran the code below, I have received the following error message:
The objects "CustomerRoot" and "CustomerRoot" in the FROM clause have the same exposed names. Use correlation names to distinguish them.
Code:
SELECT TOP 100
PEATR.[EffectiveDate] AS 'Effective Date',
CustomerRoot.[CustomerName] AS 'Name',
CustomerAddressRoot.[Street1] AS 'Address 1',
CustomerAddressRoot.[Street2] AS 'Address 2',
CustomerAddressRoot.[City],
CustomerAddressRoot.[State],
CustomerAddressRoot.[Zip],
CustomerAddressRoot.[Country],
CustomerAddressRoot.[AddressDesc] AS 'Description'
FROM PrEmployeeAccrueTierRoot AS PEATR, CustomerRoot, CustomerAddressRoot
INNER JOIN CustomerRoot ON CustomerAddressRoot.CustomerId=CustomerRoot.CustomerId
I did assign aliases to all of the tables previously, though I was still returning the same error message. Any guidance or suggestions would be much appreciated.
You are performing a cartesian join.
FROM PrEmployeeAccrueTierRoot AS PEATR, CustomerRoot, CustomerAddressRoot
...is the same as...
FROM PrEmployeeAccrueTierRoot AS PEATR
inner join CustomerRoot on 1=1
inner join CustomerAddressRoot on 1=1
There is no join logic.
So, if PrEmployeeAccrueTierRoot has 1000 rows and CustomerRoot has 1000 rows and CustomerAddressRoot has 1000 rows, your result will have 1,000,000,000 rows.
Try two things:
Include join logic.
Your query should look something like this:
SELECT TOP 100
PEATR.[EffectiveDate] AS 'Effective Date',
CustomerRoot.[CustomerName] AS 'Name',
CustomerAddressRoot.[Street1] AS 'Address 1',
CustomerAddressRoot.[Street2] AS 'Address 2',
CustomerAddressRoot.[City],
CustomerAddressRoot.[State],
CustomerAddressRoot.[Zip],
CustomerAddressRoot.[Country],
CustomerAddressRoot.[AddressDesc] AS 'Description'
FROM PrEmployeeAccrueTierRoot AS PEATR
inner join CustomerRoot on CustomerRoot.customerrootid = peatr.customerrootid
inner join CustomerAddressRoot on CustomerAddressRoot.customerrootid = CustomerRoot.customerrootid
ORDER BY CustomerRoot.[CustomerName]
Of course, I don't know what columns you should actually join on. Know thy data.
Then you'll have one problem remaining: If your query (without the TOP 100) would return millions of rows, you're asking the database server to perform all of the logic and gather all of the rows, then sort them by CustomerName, then return the first 100 rows. That could still be slow. You'll want to...
Apply filters.
SELECT TOP 100
PEATR.[EffectiveDate] AS 'Effective Date',
CustomerRoot.[CustomerName] AS 'Name',
CustomerAddressRoot.[Street1] AS 'Address 1',
CustomerAddressRoot.[Street2] AS 'Address 2',
CustomerAddressRoot.[City],
CustomerAddressRoot.[State],
CustomerAddressRoot.[Zip],
CustomerAddressRoot.[Country],
CustomerAddressRoot.[AddressDesc] AS 'Description'
FROM PrEmployeeAccrueTierRoot AS PEATR
inner join CustomerRoot on CustomerRoot.customerrootid = peatr.customerrootid
inner join CustomerAddressRoot on CustomerAddressRoot.customerrootid = CustomerRoot.customerrootid
WHERE CustomerAddressRoot.State = 'Alaska'
ORDER BY CustomerRoot.[CustomerName]
..at least during testing, to speed things up.

SQL query table inner join

I'm having a issue where the SKU doesn't match the correct lines via the color. The csv rows / items do not match and there seems to be a lot of duplicates the DIM_1_UPR field in the csv needs to match the SKU, BARCODE, and VENDOR_SKU fields. I think I messed up my inner join.
Here is a screen shot with one item.. you can see it is showing 288 rows. It is duplicating the same thing multiple times and the SKU / VENDOR_SKU / BARCODE basically everything from USR_MAG_ITEM_EXP doesn't match or line up correctly with the rest of the table :
Do I have to do all keys or can I just use the one ITEM_NO?
Keys
Here is my code:
SELECT
dbo.IM_PRC.ITEM_NO, dbo.IM_PRC.REG_PRC, dbo.IM_PRC.PRC_1,
dbo.IM_PRC.PRC_2,dbo.IM_ITEM.CATEG_COD,
dbo.IM_ITEM.SUBCAT_COD, dbo.IM_ITEM.STAT, dbo.IM_ITEM.LST_COST,
dbo.IM_ITEM.USER_MAG_NAME, dbo.IM_INV_CELL.LOC_ID,
dbo.IM_INV_CELL.DIM_1_UPR, dbo.IM_INV_CELL.MIN_QTY, dbo.IM_INV_CELL.MAX_QTY,
dbo.IM_INV_CELL.QTY_ON_HND, dbo.USR_MAG_ITEM_EXP.SKU,
dbo.USR_MAG_ITEM_EXP.VENDOR_SKU,
dbo.USR_MAG_ITEM_EXP.BARCOD
FROM dbo.IM_PRC
INNER JOIN dbo.IM_ITEM ON dbo.IM_PRC.ITEM_NO = dbo.IM_ITEM.ITEM_NO
INNER JOIN dbo.IM_INV_CELL ON dbo.IM_INV_CELL.ITEM_NO = dbo.IM_PRC.ITEM_NO
INNER JOIN dbo.USR_MAG_ITEM_EXP ON dbo.USR_MAG_ITEM_EXP.ITEM_NO =
dbo.IM_PRC.ITEM_NO
WHERE dbo.IM_INV_CELL.LOC_ID IN ('01', '03', '11', '12', '14', '23') and
dbo.IM_ITEM.ITEM_NO = 'grohrostbk'
ORDER BY IM_INV_CELL.LOC_ID ASC
Edit : so doing a full outter join and adding the extra syntax for joining that aaron suggested gave me no duplicates! But
how do I include our parent products that do not have a color or add a empty DIM_1_UPR for example I want the top line to be included in the major sheet - SELECT top 5 item_no, name, sku, DIM_1_UPR, vendor_sku FROM dbo.USR_MAG_ITEM_EXP WHERE ITEM_NO = 'grohrostbk' screen: pic
If you look at the screen shot screen you can see that the first LINE has a DIM_1_UPR of "*" and a VENDOR_SKU of "HROSTBK" but when I run the main joined sheet I do not see this LINE because it has a * and no color. Any thoughts on how to include it?

Grouping by all non-aggregated columns in MSSQL

Suppose I have two tables PO and PO_Line and I want to list all fields from PO plus the quantity of rows from PO_Line that link back to each row in PO I would write a query something like -
SELECT
PO.propA,
PO.propB,
PO.propC,
PO.propD,
PO.propE,
...
PO.propY,
COUNT(PO_Line.propA) LINES
FROM
PO
LEFT JOIN
PO_Lines
ON
PO.ID = PO_Lines.PO_ID
Obviously this would give an error someting along the lines of -
Column 'PO.propA' is invaalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
So to get the query to run I will add a GROUP BY clause to the end of the query and copy and paste my select lines, like so -
SELECT
PO.propA,
PO.propB,
PO.propC,
PO.propD,
PO.propE,
...
PO.propY,
COUNT(PO_Line.propA) LINES
FROM
PO
LEFT JOIN
PO_Lines
ON
PO.ID = PO_Lines.PO_ID
GROUP BY
PO.propA,
PO.propB,
PO.propC,
PO.propD,
PO.propE,
...
PO.propY
Which works perfectly however it all feels a little unwieldy, especially if I've named my columns i.e. -
SELECT
PO.propA AS 'FIRST PROPERTY',
PO.propB AS 'SECOND PROPERTY',
PO.propC AS 'THIRD PROPERTY',
PO.propD AS 'ANOTHER PROPERTY',
PO.propE AS 'YOU GET THE IDEA',
...
PO.propY
and I have to copy/paste the entries from the select clause and then delete the column names.
So my question is - Is there a shorthand method to say group by all non-aggregated entries found in the select clause?
I think you just want window functions:
SELECT . . .,
COUNT(PO_Line.propA) OVER (PARTITION BY PO.ID) as LINES
FROM PO LEFT JOIN
PO_Lines
ON PO.ID = PO_Lines.PO_ID;
I have to copy/paste the entries from the select clause and then delete the column names.
I strongly suggest to use block/column selection.Move , as first element and allign your aliases:
SELECT
PO.propA AS 'FIRST PROPERTY'
,PO.propB AS 'SECOND PROPERTY'
,PO.propC AS 'THIRD PROPERTY'
,PO.propD AS 'ANOTHER PROPERTY'
,PO.propE AS 'YOU GET THE IDEA'
...
,PO.propY
,COUNT(PO_Line.propA) LINES
FROM PO
LEFT JOIN PO_Lines
ON PO.ID = PO_Lines.PO_ID
GROUP BY
...
In SQL Server Management Studio use simple block selection SHIFT + ALT highlight and paste.
If you are using other editor find corresponding keyshortcut here.
It is nice for multiple edit at once like adding schema, alias, ...and so on.
Reading your query I think you might not need a GROUP BY to begin with:
SELECT
PO.propA,
PO.propB,
PO.propC,
PO.propD,
PO.propE,
...
PO.propY,
(SELECT COUNT(*) FROM PO_Lines WHERE PO.ID = PO_Lines.PO_ID) LINES
FROM
PO

SQL Join Problems

I'm having a problem that I assume is related to the Join in my SQL statement.
select s.customer as 'Customer',
s.store as 'Store',
s.item as 'Item',
d.dlvry_dt as 'Delivery',
i.item_description as 'Description',
mj.major_class_description as 'Major Description',
s.last_physical_inventory_dt as 'Last Physical Date',
s.qty_physical as 'Physical Qty',
s.avg_unit_cost as 'Unit Cost',
[qty_physical]*[avg_unit_cost] as Value
from argus.DELIVERY d
join argus.STORE_INVENTORY s
ON (s.store = d.store)
join argus.ITEM_MASTER i
ON (s.item = i.item)
join argus.MINOR_ITEM_CLASS mi
ON (i.minor_item_class = mi.minor_item_class)
join argus.MAJOR_ITEM_CLASS mj
ON (mi.major_item_class = mj.major_item_class)
where s.last_physical_inventory_dt between '6/29/2011' and '7/2/2012'
and s.customer = '20001'
and s.last_physical_inventory_dt IS NOT NULL
It comes back with a seemingly infinite amount of copies of one record. Is there something wrong with the way I'm joining these tables?
join argus.MINOR_ITEM_CLASS mi
ON (i.minor_item_class = mi.minor_item_class)
join argus.MAJOR_ITEM_CLASS mj
ON (mi.major_item_class = mj.major_item_class)
My guess is that your error resides in one of these 2 joins. When you only use the word JOIN it assumes that you are trying to do an INNER JOIN which returns all records that have at least 1 to 1. I don't know what your data looks like but I am assuming that there is a many to many relationship between minor item class and major item class so when you run this query you are receiving duplicated records for almost every field, but the major item class differs.
I would look at the results. Most of the columns will have repeating data that doesn't change while one of the columns will have a different value for every row. That should tell you that the column with differing data for each row is the column that you should be joining differently.
Otherwise, I would say that your query is formatted correctly.

SQL query question

So...I'm new to sql and loving what I've learned, but here is a question I'm stumped on.
I've created a website form. It's a timecard type form. A user logs on and clicks a pull down menu (which is being selected from the DB) It's called jobsite, then he scrolls down and clicks Jobsite#2. (both fields are selecting from the same table..) When they submit, it submits into the DB just fine. Showing both fields as the ID number they picked.. Not the name..
SELECT jobsite.Jobsite as 'Customer',
FROM timeCard
LEFT JOIN jobsite ON timeCard.jobsite = jobsite.id
That query works great. Pulling timeCard.jobsite information. If I change it to
LEFT JOIN jobsite ON timeCard.jobsite2 = jobsite.id
That works great too pulling all the inputted data from Jobsite2...What query will work to get them to show as 'Customer 1, and Customer2' on the same query? Does my question make sense? I'm trying to get it to export into Excel so that it would show up with all the information on one line basically. Employee 1, worked at jobsite 1 and jobsite 4 (but instead show: Employee (me) worked at (this place) and (that place)
Where both jobsites come from the same table in the DB
Thanks for any help you guys/gals can give
You're going to need to join to the jobsite table twice, because one timecard record is associated with two different jobsite records (assuming some things about your schema and DBMS...):
SELECT t.EmployeeName, j1.jobsite AS 'Customer 1', j2.jobsite AS 'Customer 2'
FROM timecard t
LEFT JOIN jobsite j1 ON t.jobsite = j1.id
LEFT JOIN jobsite j2 ON t.jobsite2 = j2.id
SELECT js1.jobsite AS customer1, js2.jobsite AS customer2
FROM timecard tc
LEFT JOIN
jobsite js1
ON js1.id = tc.jobsite
LEFT JOIN
jobsite js2
ON js2.id = tc.jobsite2
Are you asking for something like this?
SELECT jobsite.Jobsite as 'Customer',
FROM timeCard, jobSite
WHERE timeCard.jobsite = jobsite.id
OR timeCard.jobsite2 = jobsite.id
(PS. Since you mentioned you are new to SQL, I'd like to take this opportunity to make sure you know about parameterized queries (articles on ASP.Net, PHP), which you should always be using instead of concatenating strings)