SQL Union All alias from first table? - mysql

I have two tables
[data] - title,maker,partnum,price
[cross] - product(data.partnum),title,maker,partnum,price
What I want is listing all product via sysn number. How can I get with union all data like that with ordering ->
[data table] Microsoft, "some note", 9989, $20
[cross table] Microsoft reseller, "some note", 1045, $30
[cross table] Apple reseller in Microsoft :), "some note", 2233, $40
virtual spacer :)
[data table] Microsoft, "some note", 9989, $10
[cross table] Lenovo reseller in Microsoft..
Im trying with this
SELECT `title`,'Microsoft' AS `maker`,`partnum`,`price`
FROM data as d
WHERE sysn=%s
GROUP BY partnum
UNION ALL
SELECT `title`,`maker`,`partnum`,`price`
FROM cross as c
WHERE c.product=d.partnum
GROUP BY `partnum`
Thanks

It's not entirely clear what you are asking. Consider setting up an example schema and data in http://sqlfiddle.com.
A "virtual spacer" is going to be very messy to achieve. It's not totally impossible, just messy.
For returning rows in a particular sequence, you are going to need to add an ORDER BY clause.
It's not at all clear why you are including GROUP BY clauses. The GROUP BY on the first SELECT would effectively "collapse" example output rows 1. and 5. given the same value 9989 for partnum. Absent an explanation of why you need a GROUP BY, I'm going to guess that what you really intended was an ORDER BY clause.
It's also not clear why the literal value 'Microsoft' would need to appear in the SELECT list, in place of the maker column from the data table. There's nothing invalid SQL-wise with doing that. But absent an explanation, it just doesn't make much sense.
The question we should to ask... Why is this specific result needed? Is there a different result which would be easier to achieve, which would equally satisfy the requirements?
Setting aside the "virtual spacer" row, the return from a query like this seems like it satisfies most of the specification:
SELECT t.src
, t.title
, t.maker
, t.partnum
, t.price
FROM (
SELECT '[data]' AS `src`
, d1.title AS `title`
, d1.maker AS `maker`
, d1.partnum AS `partnum`
, d1.price AS `price`
, d1.partnum AS `product`
FROM data d1
WHERE d1.sysn = ?
UNION ALL
SELECT '[cross]'
, c2.title
, c2.maker
, c2.partnum
, c2.price
, c2.product
FROM cross c2
JOIN data d2
ON d2.partnum = c2.product
WHERE d2.sysn = ?
)
ORDER BY t.product DESC, t.src DESC, t.price ASC

If you are using MySQL, "cross" is a reserved word and you must enclose cross in backticks to use it as a table name (The backtick is next the the '1' on the keyboard on the upper left).

Related

SQL Query with Foreign Key (missing data, return default value)

I have a table called
"machine" (columns: machine_id(pk),year, site, color)
and a table called
"machine_description" (columns: machine_id(fk), language, description)
I would like to create a sql query where I can type in the preferred language and it returns all machines with the appropriate description in the preferred language. (I have made it)
SELECT *
FROM machine
LEFT JOIN machine_description ON machine.machine_id = machine_description.machine_id
WHERE machine_description.description = "german";
My problem, however, is that with some machines the description is not available in the desired language. In this case, the description should be returned in english by default instead of the desired language.
How can I solve this problem?
See Image
Thank you very much for your answer.
PS. I am quite new in this field...
enter image description here
As of MySQL 8 you can use window functions for the ranking (select both German and English first, then rank the former higher than the latter, and keep the better ranked rows):
select *
from
(
select
m.*,
md.*,
row_number() over (partition by m.machine_id order by language desc) as rn
from machine m
join machine_description md on md.machine_id = m. machine_id
and md.language in ('german', 'english')
) both
where rn = 1;
Make this a left outer join, if you want to allow for the case that neither the desired language nor English is available and you want to show the machine still.
But you can probably also use a subquery in the select clause:
select m.*
(
select md.description
from machine_description md
where md.machine_id = m. machine_id
and md.language in ('german', 'english')
order by md.language desc -- German before English
limit 1
) as descr
from machine m;
I am sorting by language descending so as to get German before English. For a more general solution sort with CASE WHEN:
order by case when md.language = 'english' then 1 else 0 end
or just
order by (md.language = 'english')
because true is 1 and false is 0 in MySQL.

What is the proper MySQL way to take data from 4 rows, 1 column, and separate into 9 columns?

I've studied and tried days worth of SQL queries to find "something" that will work. I have a table, apj32_facileforms_subrecords, that uses 7 columns. All the data I want to display is in 1 column - "value". The "record" displays the number of the entry. The "title" is what I would like to appear in the header row, but that's not as important as "value" to display in 1 row based upon "record" number.
I've tried a lot of CONCAT and various Pivot queries, but nothing seems to do more than "get close" to what I'd like as the end result.
Here's a screen shot of the table:
The output "should" be linear, so that 1 row contains 9 columns:
Project; Zipcode; First Name; Last Name; Address; City; Phone; E-mail; Trade (in that order). And the values in the 9 columns come from "value" as they relate to the "record" number.
I know there are LOT of examples that are similar, but nothing I've found covers taking all the values from "value" and CONCAT to 1 row.
This works to get all the data I want - SELECT record,value FROM apj32_facileforms_subrecords WHERE (record IN (record,value)) ORDER BY record
But the values are still in multiple rows. I can play with that query to get just the values, but I'm still at a loss to get them into 1 row. I'll keep playing with that query to see if I can figure it out before one of the experts here shows me how simple it is to do that.
Any help would be appreciated.
Using SQL to flatten an EAV model representation into a relational representation can be somewhat convoluted, and not very efficient.
Two commonly used approaches are conditional aggregation and correlated subqueries in the SELECT list. Both approaches call out for careful indexing for suitable performance with large sets.
correlated subqueries example
Here's an example of the correlated subquery approach, to get one value of the "zipcode" attribute for some records
SELECT r.id
, ( SELECT v1.value
FROM `apj32_facileforms_subrecords` v1
WHERE v1.record = r.id
AND v1.name = 'zipcode'
ORDER BY v1.value LIMIT 0,1
) AS `Zipcode`
FROM ( SELECT 1 AS id ) r
Extending that, we repeat the correlated subquery, changing the attribute identifier ('firstname' in place of 'zipcode'. looks like we we could also reference it by element, e.g. v2.element = 2
SELECT r.id
, ( SELECT v1.value
FROM `apj32_facileforms_subrecords` v1
WHERE v1.record = r.id
AND v1.name = 'zipcode'
ORDER BY v1.value LIMIT 0,1
) AS `Zipcode`
, ( SELECT v2.value
FROM `apj32_facileforms_subrecords` v2
WHERE v2.record = r.id
AND v2.name = 'firstname'
ORDER BY v2.value LIMIT 0,1
) AS `First Name`
, ( SELECT v3.value
FROM `apj32_facileforms_subrecords` v3
WHERE v3.record = r.id
AND v3.name = 'lastname'
ORDER BY v3.value LIMIT 0,1
) AS `Last Name`
FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r
returns something like
id Zipcode First Name Last Name
-- ------- ---------- ---------
1 98228 David Bacon
2 98228 David Bacon
conditional aggregation approach example
We can use GROUP BY to collapse multiple rows into one row per entity, and use conditional tests in expressions to "pick out" attribute values with aggregate functions.
SELECT r.id
, MIN(IF(v.name = 'zipcode' ,v.value,NULL)) AS `Zip Code`
, MIN(IF(v.name = 'firstname' ,v.value,NULL)) AS `First Name`
, MIN(IF(v.name = 'lastname' ,v.value,NULL)) AS `Last Name`
FROM ( SELECT 1 AS id UNION ALL SELECT 2 ) r
LEFT
JOIN `apj32_facileforms_subrecords` v
ON v.record = r.id
GROUP
BY r.id
For more portable syntax, we can replace MySQL IF() function with more ANSI standard CASE expression, e.g.
, MIN(CASE v.name WHEN 'zipcode' THEN v.value END) AS `Zip Code`
Note that MySQL does not support SQL Server PIVOT syntax, or Oracle MODEL syntax, or Postgres CROSSTAB or FILTER syntax.
To extend either of these approaches to be dynamic, to return a resultset with a variable number of columns, and variety of column names ... that is not possible in the context of a single SQL statement. We could separately execute SQL statements to retrieve information, that would allow us to dynamically construct a SQL statement of a form show above, with an explicit set of columns to be returned.
The approaches outline above return a more traditional relational model, (individual columns each with a value).
non-relational munge of attributes and values into a single string
If we have some special delimiters, we could munge together a representation of the data using GROUP_CONCAT function
As a rudimentary example:
SELECT r.id
, GROUP_CONCAT(v.title,'=',v.value ORDER BY v.name) AS vals
FROM ( SELECT 1 AS id ) r
LEFT
JOIN `apj32_facileforms_subrecords` v
ON v.record = r.id
AND v.name in ('zipcode','firstname','lastname')
GROUP
BY r.id
To return two columns, something like
id vals
-- ---------------------------------------------------
1 First Name=David,Last Name=Bacon,Zip Code=98228
We need to be aware that the return from GROUP_CONCAT is limited to group_concat_max_len bytes. And here we have just squeezed the balloon, moving the problem to some later processing, to parse the resulting string. If we have any equal signs or commas that appear in the values, it's going to make a mess of parsing the result string. So we will have to properly escape any delimiters that appear in the data, so that GROUP_CONCAT expression is going to get more involved.

mysql multiple similar table query[seems not duplicate]

I have a sales software that use MYSQL database and i want to make a web extension using PHP. the software creating a new table everyday for every days transaction with same column but name like sales_data_Yearmonthday.
e.g
sales_data_20190122
sales_data_20190123
sales_data_20190124
sales_data_20190125
sales_data_20190126
sales_data_20190127
sales_data_20190128
So my question is what will be the best way to query these table if i want to get sales report for last 7 days?
UNION ALL is one option to join all table but are there any other option to do that for getting best performance as 356 table will be created every year and each table may have contain over 5000 records.
its may not the best database design but i cannot change it.
Given the specified constraints (as unfortunate as that situation is)...
using UNION ALL is the most appropriate solution to satisfying the specification.
If we are wanting the "past seven days", then we (our code) needs to figure out which tables will be required (vs the tables that would be required e.g. "so far this month") and dynamically construct SQL text.
We first write the query against one table, get that tested.
SELECT t.fee
, t.fi
, t.fo
, t.fum
FROM sales_data_20190128 t
WHERE t.foo = ?
Then we just repeat that query for each table that might included rows we are interested in, excluding tables we know for sure will not contain rows we want, and combine the queries with UNION ALL set operator.
If we need the whole set ordered, then wrap each SELECT in parens, and finish with an ORDER BY clause. e.g.
( SELECT t.fee, t.fi, t.fo, t.fum
FROM sales_data_20190124 t
WHERE t.foo = ?
)
UNION ALL
( SELECT t.fee, t.fi, t.fo, t.fum
FROM sales_data_20190125
WHERE t.foo = ?
)
UNION ALL
( SELECT t.fee, t.fi, t.fo, t.fum
FROM sales_data_20190126 t
WHERE t.foo = ?
)
UNION ALL
( SELECT t.fee, t.fi, t.fo, t.fum
FROM sales_data_20190127 t
WHERE t.foo = ?
)
UNION ALL
( SELECT t.fee, t.fi, t.fo, t.fum
FROM sales_data_20190128 t
WHERE t.foo = ?
)
ORDER BY 1,2
Do NOT try to simplify the code by creating view that concatenates all of the tables together, and query against that. Don't do that.

sql select to extract and link the record above

I need some assistance with my extract. Below is a view of my data and how it is extract from a MS SQL database.
My challenge is that the database does not differentiate from the different "email address" . How do I link email address record to the record above.
Secid|Name|Question|Answer|
2|load1|Name of Principle|Joe Make|
2|load1|Contact Number|12234423|
2|load1|Email address|joemake#mymail.com|
2|load1|Name of Principle|Amy Soup|
2|load1|Contact Number of Principle|23134|
2|load1|Email address|amysoup#mymail.com|
2|load1|Name of Teacher|james blue|
2|load1|Contact Number|8787878|
2|load1|Email Address|jamesblue#mymail.com|
2|load1|Name of Secretary|CHARLES black|
2|load1|Contact Number|989897|
2|load1|Email Address|chblack#mymail.com|
If you don't have any column to order by (e.g. a monotonically increasing identity column, or a timestamp), I'm afraid you're honestly out of luck. There is no way to guarantee any sort of ordering of the rows for any query.
What you can do, however, is export the data into an Excel sheet and then look at it manually and put the rows in the right order, assuming you can figure it out. Unfortunately this is really going to be the only way.
If you had a column you could order by, you can use a join to group the rows, assuming you had a way of identifying the start of each set - in your case a Question like 'Name of %' should probably work. Assuming an identity column called Id, something like:
select t.*, tGroupStart.Id as GroupId
from myTable t
join myTable tGroupStart on tGroupStart.Id <= t.Id
and tGroupStart.Question like 'Name of %'
where not exists (
select 1
from myTable t2
where t2.Id <= t.Id
and t2.Question like 'Name of %'
and t2.Id > tGroupStart.Id
)

mySQL error need some help

I am trying to run a nested query but I am getting this error,
#1241 - Operand should contain 1 column(s)
this is the query that I am trying to run,
SELECT *
FROM `categoryTable`
WHERE `categoryId` NOT
IN (
SELECT `categoryTable`.`categoryId` , `categoryTable`.`categoryTitle` , `userMenuTable`.`menuEntryId`
FROM (
`categoryTable`
)
LEFT JOIN `userMenuTable` ON `categoryTable`.`categoryId` = `userMenuTable`.`categoryId`
WHERE `userMenuTable`.`cookieId` = 'bang4b696152b4869'
)
LIMIT 0 , 30
5th line should be
SELECT `categoryTable`.`categoryId`
i.e. it should only reference categoryId.
In other words, with the WHERE xyz [NOT] IN (SELECT ... predicate, there should only be one column in the nested select, one corresponding to the "xyz" column but of course not necessarily named the same. The reason is that SQL wouldn't know which column of the nested query to use for comparing with the "xyz" column; a lesser reason is that the other columns are useless, why bring them in?
Yes. I agree with #mjv, basically you are checking to see if categoryId is not in the list of
`SELECT `categoryTable`.`categoryId` , `categoryTable`.`categoryTitle` , `userMenuTable`.`menuEntryId`
FROM (
`categoryTable`
`
So you need to mention only one field categoryID and it will check to see if it is not in this list.
Hope this makes some sense.